blob: 0bb3e431ee01e6ecd7b46629d71096d1703dbdb4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French2dd29d32007-04-23 22:07:35 +00004 * Copyright (C) International Business Machines Corp., 2002,2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000037#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000062 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000063#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000064 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 {BAD_PROT, "\2"}
66};
67#endif
68
Steve French39798772006-05-31 22:40:51 +000069/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000072#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000073#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000087static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000096 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve French26f57362007-08-30 22:09:15 +000097 if (open_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 open_file->invalidHandle = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
105/* If the return code is zero, this function must fill in request_buf pointer */
106static int
107small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
108 void **request_buf /* returned */)
109{
110 int rc = 0;
111
112 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
113 check for tcp and smb session status done differently
114 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000115 if (tcon) {
116 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800117 /* only tree disconnect, open, and write,
118 (and ulogoff which does not have tcon)
119 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000120 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000121 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800122 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000123 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800124 smb_command));
125 return -ENODEV;
126 }
127 }
Steve French790fe572007-07-07 19:25:05 +0000128 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000129 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000131 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700132 reconnect, should be greater than cifs socket
133 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000134 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000135 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000137 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000138 CifsGood), 10 * HZ);
139 if (tcon->ses->server->tcpStatus ==
140 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000142 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000144 cFYI(1, ("gave up waiting on "
145 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700147 } /* else "hard" mount - keep retrying
148 until process is killed or server
149 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 } else /* TCP session is reestablished now */
151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Steve French50c2f752007-07-13 00:33:32 +0000153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 nls_codepage = load_nls_default();
155 /* need to prevent multiple threads trying to
156 simultaneously reconnect the same SMB session */
157 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000158 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000159 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700160 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000161 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000163 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000164 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000166 /* tell server which Unix caps we support */
167 if (tcon->ses->capabilities & CAP_UNIX)
168 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000169 tcon,
Steve French8af18972007-02-14 04:42:51 +0000170 NULL /* we do not know sb */,
Steve French50c2f752007-07-13 00:33:32 +0000171 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700172 /* BB FIXME add code to check if wsize needs
173 update due to negotiated smb buffer size
174 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000175 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 atomic_inc(&tconInfoReconnectCount);
177
178 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000179 /* Removed call to reopen open files here.
180 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700181 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Steve French50c2f752007-07-13 00:33:32 +0000183 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700184 know whether we can continue or not without
185 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000186 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 case SMB_COM_READ_ANDX:
188 case SMB_COM_WRITE_ANDX:
189 case SMB_COM_CLOSE:
190 case SMB_COM_FIND_CLOSE2:
191 case SMB_COM_LOCKING_ANDX: {
192 unload_nls(nls_codepage);
193 return -EAGAIN;
194 }
195 }
196 } else {
197 up(&tcon->ses->sesSem);
198 }
199 unload_nls(nls_codepage);
200
201 } else {
202 return -EIO;
203 }
204 }
Steve French790fe572007-07-07 19:25:05 +0000205 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 return rc;
207
208 *request_buf = cifs_small_buf_get();
209 if (*request_buf == NULL) {
210 /* BB should we add a retry in here if not a writepage? */
211 return -ENOMEM;
212 }
213
Steve French63135e02007-07-17 17:34:02 +0000214 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000215 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Steve French790fe572007-07-07 19:25:05 +0000217 if (tcon != NULL)
218 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000221}
222
Steve French12b3b8f2006-02-09 21:12:47 +0000223int
Steve French50c2f752007-07-13 00:33:32 +0000224small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000225 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000226{
227 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000228 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000229
Steve French5815449d2006-02-14 01:36:20 +0000230 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000231 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000232 return rc;
233
Steve French04fdabe2006-02-10 05:52:50 +0000234 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000235 buffer->Mid = GetNextMid(ses->server);
236 if (ses->capabilities & CAP_UNICODE)
237 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000238 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000239 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
240
241 /* uid, tid can stay at zero as set in header assemble */
242
Steve French50c2f752007-07-13 00:33:32 +0000243 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000244 this function is used after 1st of session setup requests */
245
246 return rc;
247}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
249/* If the return code is zero, this function must fill in request_buf pointer */
250static int
251smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
252 void **request_buf /* returned */ ,
253 void **response_buf /* returned */ )
254{
255 int rc = 0;
256
257 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
258 check for tcp and smb session status done differently
259 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000260 if (tcon) {
261 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800262 /* only tree disconnect, open, and write,
263 (and ulogoff which does not have tcon)
264 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000265 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800266 (smb_command != SMB_COM_OPEN_ANDX) &&
267 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000268 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800269 smb_command));
270 return -ENODEV;
271 }
272 }
273
Steve French790fe572007-07-07 19:25:05 +0000274 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000275 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700277 /* Give Demultiplex thread up to 10 seconds to
278 reconnect, should be greater than cifs socket
279 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000280 while (tcon->ses->server->tcpStatus ==
281 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000283 (tcon->ses->server->tcpStatus ==
284 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000285 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700286 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000288 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000290 cFYI(1, ("gave up waiting on "
291 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700293 } /* else "hard" mount - keep retrying
294 until process is killed or server
295 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 } else /* TCP session is reestablished now */
297 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 nls_codepage = load_nls_default();
300 /* need to prevent multiple threads trying to
301 simultaneously reconnect the same SMB session */
302 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000303 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000304 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700305 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000306 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700308 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
309 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000311 /* tell server which Unix caps we support */
312 if (tcon->ses->capabilities & CAP_UNIX)
313 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000314 tcon,
Steve French8af18972007-02-14 04:42:51 +0000315 NULL /* do not know sb */,
316 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700317 /* BB FIXME add code to check if wsize needs
318 update due to negotiated smb buffer size
319 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000320 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 atomic_inc(&tconInfoReconnectCount);
322
323 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000324 /* Removed call to reopen open files here.
325 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700326 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Steve French50c2f752007-07-13 00:33:32 +0000328 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700329 know whether we can continue or not without
330 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000331 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 case SMB_COM_READ_ANDX:
333 case SMB_COM_WRITE_ANDX:
334 case SMB_COM_CLOSE:
335 case SMB_COM_FIND_CLOSE2:
336 case SMB_COM_LOCKING_ANDX: {
337 unload_nls(nls_codepage);
338 return -EAGAIN;
339 }
340 }
341 } else {
342 up(&tcon->ses->sesSem);
343 }
344 unload_nls(nls_codepage);
345
346 } else {
347 return -EIO;
348 }
349 }
Steve French790fe572007-07-07 19:25:05 +0000350 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return rc;
352
353 *request_buf = cifs_buf_get();
354 if (*request_buf == NULL) {
355 /* BB should we add a retry in here if not a writepage? */
356 return -ENOMEM;
357 }
358 /* Although the original thought was we needed the response buf for */
359 /* potential retries of smb operations it turns out we can determine */
360 /* from the mid flags when the request buffer can be resent without */
361 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000362 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000363 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
366 wct /*wct */ );
367
Steve French790fe572007-07-07 19:25:05 +0000368 if (tcon != NULL)
369 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return rc;
372}
373
Steve French50c2f752007-07-13 00:33:32 +0000374static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376 int rc = -EINVAL;
377 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000378 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 /* check for plausible wct, bcc and t2 data and parm sizes */
381 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000382 if (pSMB->hdr.WordCount >= 10) {
383 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
385 /* check that bcc is at least as big as parms + data */
386 /* check that bcc is less than negotiated smb buffer */
387 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000388 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000389 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000390 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000392 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700393 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000395 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000396 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
398 return 0;
399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
401 }
402 }
Steve French50c2f752007-07-13 00:33:32 +0000403 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 sizeof(struct smb_t2_rsp) + 16);
405 return rc;
406}
407int
408CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
409{
410 NEGOTIATE_REQ *pSMB;
411 NEGOTIATE_RSP *pSMBr;
412 int rc = 0;
413 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000414 int i;
Steve French50c2f752007-07-13 00:33:32 +0000415 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000417 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100418 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Steve French790fe572007-07-07 19:25:05 +0000420 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 server = ses->server;
422 else {
423 rc = -EIO;
424 return rc;
425 }
426 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
427 (void **) &pSMB, (void **) &pSMBr);
428 if (rc)
429 return rc;
Steve French750d1152006-06-27 06:28:30 +0000430
431 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000432 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000433 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000434 else /* if override flags set only sign/seal OR them with global auth */
435 secFlags = extended_security | ses->overrideSecFlg;
436
Steve French762e5ab2007-06-28 18:41:42 +0000437 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000438
Steve French1982c342005-08-17 12:38:22 -0700439 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000440 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000441
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000442 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000443 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000444 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
445 cFYI(1, ("Kerberos only mechanism, enable extended security"));
446 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
447 }
Steve French50c2f752007-07-13 00:33:32 +0000448
Steve French39798772006-05-31 22:40:51 +0000449 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000450 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000451 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
452 count += strlen(protocols[i].name) + 1;
453 /* null at end of source and target buffers anyway */
454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 pSMB->hdr.smb_buf_length += count;
456 pSMB->ByteCount = cpu_to_le16(count);
457
458 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000460 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000461 goto neg_err_exit;
462
Al Viro733f99a2006-10-14 16:48:26 +0100463 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000464 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000465 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000466 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000467 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000468 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000469 could not negotiate a common dialect */
470 rc = -EOPNOTSUPP;
471 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000472#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000473 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100474 && ((dialect == LANMAN_PROT)
475 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000476 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000477 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000478
Steve French790fe572007-07-07 19:25:05 +0000479 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000480 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000481 server->secType = LANMAN;
482 else {
483 cERROR(1, ("mount failed weak security disabled"
484 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000485 rc = -EOPNOTSUPP;
486 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000487 }
Steve French254e55e2006-06-04 05:53:15 +0000488 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
489 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
490 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000491 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000492 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
493 /* even though we do not use raw we might as well set this
494 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000495 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000496 server->maxRw = 0xFF00;
497 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
498 } else {
499 server->maxRw = 0;/* we do not need to use raw anyway */
500 server->capabilities = CAP_MPX_MODE;
501 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000502 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000503 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000504 /* OS/2 often does not set timezone therefore
505 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000506 * Could deviate slightly from the right zone.
507 * Smallest defined timezone difference is 15 minutes
508 * (i.e. Nepal). Rounding up/down is done to match
509 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000510 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000511 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000512 struct timespec ts, utc;
513 utc = CURRENT_TIME;
514 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
515 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000516 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
517 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000518 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000519 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000520 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000521 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000522 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000523 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000524 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000525 if (val < 0)
Steve Frenchb815f1e2006-10-02 05:53:29 +0000526 result = - result;
527 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000528 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000529 server->timeAdj = (int)tmp;
530 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000531 }
Steve French790fe572007-07-07 19:25:05 +0000532 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000533
Steve French39798772006-05-31 22:40:51 +0000534
Steve French254e55e2006-06-04 05:53:15 +0000535 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000536 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000537
Steve French50c2f752007-07-13 00:33:32 +0000538 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000539 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000540 memcpy(server->cryptKey, rsp->EncryptionKey,
541 CIFS_CRYPTO_KEY_SIZE);
542 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
543 rc = -EIO; /* need cryptkey unless plain text */
544 goto neg_err_exit;
545 }
Steve French39798772006-05-31 22:40:51 +0000546
Steve French790fe572007-07-07 19:25:05 +0000547 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000548 /* we will not end up setting signing flags - as no signing
549 was in LANMAN and server did not return the flags on */
550 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000551#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000552 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000553 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000554 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000555 rc = -EOPNOTSUPP;
556#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000557 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000558 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000559 /* unknown wct */
560 rc = -EOPNOTSUPP;
561 goto neg_err_exit;
562 }
563 /* else wct == 17 NTLM */
564 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000565 if ((server->secMode & SECMODE_USER) == 0)
566 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000567
Steve French790fe572007-07-07 19:25:05 +0000568 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000569#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000570 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000571#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000572 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000573 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000574
Steve French790fe572007-07-07 19:25:05 +0000575 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000576 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000577 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000578 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000579 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000580 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000581 else if (secFlags & CIFSSEC_MAY_KRB5)
582 server->secType = Kerberos;
583 else if (secFlags & CIFSSEC_MAY_LANMAN)
584 server->secType = LANMAN;
585/* #ifdef CONFIG_CIFS_EXPERIMENTAL
586 else if (secFlags & CIFSSEC_MAY_PLNTXT)
587 server->secType = ??
588#endif */
589 else {
590 rc = -EOPNOTSUPP;
591 cERROR(1, ("Invalid security type"));
592 goto neg_err_exit;
593 }
594 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000595
Steve French254e55e2006-06-04 05:53:15 +0000596 /* one byte, so no need to convert this or EncryptionKeyLen from
597 little endian */
598 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
599 /* probably no need to store and check maxvcs */
600 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000602 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
603 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
604 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
605 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000606 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
607 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000608 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
609 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
610 CIFS_CRYPTO_KEY_SIZE);
611 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
612 && (pSMBr->EncryptionKeyLength == 0)) {
613 /* decode security blob */
614 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
615 rc = -EIO; /* no crypt key only if plain text pwd */
616 goto neg_err_exit;
617 }
618
619 /* BB might be helpful to save off the domain of server here */
620
Steve French50c2f752007-07-13 00:33:32 +0000621 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000622 (server->capabilities & CAP_EXTENDED_SECURITY)) {
623 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000624 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000626 goto neg_err_exit;
627 }
628
629 if (server->socketUseCount.counter > 1) {
630 if (memcmp(server->server_GUID,
631 pSMBr->u.extended_response.
632 GUID, 16) != 0) {
633 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000634 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000635 pSMBr->u.extended_response.GUID,
636 16);
637 }
638 } else
639 memcpy(server->server_GUID,
640 pSMBr->u.extended_response.GUID, 16);
641
642 if (count == 16) {
643 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000644 } else {
645 rc = decode_negTokenInit(pSMBr->u.extended_response.
646 SecurityBlob,
647 count - 16,
648 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000649 if (rc == 1) {
Steve French254e55e2006-06-04 05:53:15 +0000650 /* BB Need to fill struct for sessetup here */
651 rc = -EOPNOTSUPP;
652 } else {
653 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
Steve French254e55e2006-06-04 05:53:15 +0000656 } else
657 server->capabilities &= ~CAP_EXTENDED_SECURITY;
658
Steve French6344a422006-06-12 04:18:35 +0000659#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000660signing_check:
Steve French6344a422006-06-12 04:18:35 +0000661#endif
Steve French762e5ab2007-06-28 18:41:42 +0000662 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
663 /* MUST_SIGN already includes the MAY_SIGN FLAG
664 so if this is zero it means that signing is disabled */
665 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000666 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000667 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000668 "packet signing to be enabled in "
669 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000670 rc = -EOPNOTSUPP;
671 }
Steve French50c2f752007-07-13 00:33:32 +0000672 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000673 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000674 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
675 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000676 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000677 if ((server->secMode &
678 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
679 cERROR(1,
680 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000681 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000682 } else
683 server->secMode |= SECMODE_SIGN_REQUIRED;
684 } else {
685 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000686 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000687 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000688 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 }
Steve French50c2f752007-07-13 00:33:32 +0000690
691neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700692 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000693
Steve French790fe572007-07-07 19:25:05 +0000694 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 return rc;
696}
697
698int
699CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
700{
701 struct smb_hdr *smb_buffer;
702 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
703 int rc = 0;
704 int length;
705
706 cFYI(1, ("In tree disconnect"));
707 /*
708 * If last user of the connection and
709 * connection alive - disconnect it
710 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000711 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 * to be freed and kernel thread woken up).
713 */
714 if (tcon)
715 down(&tcon->tconSem);
716 else
717 return -EIO;
718
719 atomic_dec(&tcon->useCount);
720 if (atomic_read(&tcon->useCount) > 0) {
721 up(&tcon->tconSem);
722 return -EBUSY;
723 }
724
Steve French50c2f752007-07-13 00:33:32 +0000725 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000727 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000729 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
731
Steve French790fe572007-07-07 19:25:05 +0000732 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 up(&tcon->tconSem);
734 return -EIO;
735 }
Steve French50c2f752007-07-13 00:33:32 +0000736 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700737 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if (rc) {
739 up(&tcon->tconSem);
740 return rc;
741 } else {
742 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
745 &length, 0);
746 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700747 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
749 if (smb_buffer)
750 cifs_small_buf_release(smb_buffer);
751 up(&tcon->tconSem);
752
Steve French50c2f752007-07-13 00:33:32 +0000753 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 closed on server already e.g. due to tcp session crashing */
755 if (rc == -EAGAIN)
756 rc = 0;
757
758 return rc;
759}
760
761int
762CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
763{
764 struct smb_hdr *smb_buffer_response;
765 LOGOFF_ANDX_REQ *pSMB;
766 int rc = 0;
767 int length;
768
769 cFYI(1, ("In SMBLogoff for session disconnect"));
770 if (ses)
771 down(&ses->sesSem);
772 else
773 return -EIO;
774
775 atomic_dec(&ses->inUse);
776 if (atomic_read(&ses->inUse) > 0) {
777 up(&ses->sesSem);
778 return -EBUSY;
779 }
780 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
781 if (rc) {
782 up(&ses->sesSem);
783 return rc;
784 }
785
786 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
Steve French50c2f752007-07-13 00:33:32 +0000787
Steve French790fe572007-07-07 19:25:05 +0000788 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700789 pSMB->hdr.Mid = GetNextMid(ses->server);
790
Steve French790fe572007-07-07 19:25:05 +0000791 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
793 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
794 }
795
796 pSMB->hdr.Uid = ses->Suid;
797
798 pSMB->AndXCommand = 0xFF;
799 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
800 smb_buffer_response, &length, 0);
801 if (ses->server) {
802 atomic_dec(&ses->server->socketUseCount);
803 if (atomic_read(&ses->server->socketUseCount) == 0) {
804 spin_lock(&GlobalMid_Lock);
805 ses->server->tcpStatus = CifsExiting;
806 spin_unlock(&GlobalMid_Lock);
807 rc = -ESHUTDOWN;
808 }
809 }
Steve Frencha59c6582005-08-17 12:12:19 -0700810 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700811 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000814 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 error */
816 if (rc == -EAGAIN)
817 rc = 0;
818 return rc;
819}
820
821int
Steve French2d785a52007-07-15 01:48:57 +0000822CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
823 __u16 type, const struct nls_table *nls_codepage, int remap)
824{
825 TRANSACTION2_SPI_REQ *pSMB = NULL;
826 TRANSACTION2_SPI_RSP *pSMBr = NULL;
827 struct unlink_psx_rq *pRqD;
828 int name_len;
829 int rc = 0;
830 int bytes_returned = 0;
831 __u16 params, param_offset, offset, byte_count;
832
833 cFYI(1, ("In POSIX delete"));
834PsxDelete:
835 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
836 (void **) &pSMBr);
837 if (rc)
838 return rc;
839
840 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
841 name_len =
842 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
843 PATH_MAX, nls_codepage, remap);
844 name_len++; /* trailing null */
845 name_len *= 2;
846 } else { /* BB add path length overrun check */
847 name_len = strnlen(fileName, PATH_MAX);
848 name_len++; /* trailing null */
849 strncpy(pSMB->FileName, fileName, name_len);
850 }
851
852 params = 6 + name_len;
853 pSMB->MaxParameterCount = cpu_to_le16(2);
854 pSMB->MaxDataCount = 0; /* BB double check this with jra */
855 pSMB->MaxSetupCount = 0;
856 pSMB->Reserved = 0;
857 pSMB->Flags = 0;
858 pSMB->Timeout = 0;
859 pSMB->Reserved2 = 0;
860 param_offset = offsetof(struct smb_com_transaction2_spi_req,
861 InformationLevel) - 4;
862 offset = param_offset + params;
863
864 /* Setup pointer to Request Data (inode type) */
865 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
866 pRqD->type = cpu_to_le16(type);
867 pSMB->ParameterOffset = cpu_to_le16(param_offset);
868 pSMB->DataOffset = cpu_to_le16(offset);
869 pSMB->SetupCount = 1;
870 pSMB->Reserved3 = 0;
871 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
872 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
873
874 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
875 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
876 pSMB->ParameterCount = cpu_to_le16(params);
877 pSMB->TotalParameterCount = pSMB->ParameterCount;
878 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
879 pSMB->Reserved4 = 0;
880 pSMB->hdr.smb_buf_length += byte_count;
881 pSMB->ByteCount = cpu_to_le16(byte_count);
882 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
883 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
884 if (rc) {
885 cFYI(1, ("Posix delete returned %d", rc));
886 }
887 cifs_buf_release(pSMB);
888
889 cifs_stats_inc(&tcon->num_deletes);
890
891 if (rc == -EAGAIN)
892 goto PsxDelete;
893
894 return rc;
895}
896
897int
Steve French737b7582005-04-28 22:41:06 -0700898CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
899 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
901 DELETE_FILE_REQ *pSMB = NULL;
902 DELETE_FILE_RSP *pSMBr = NULL;
903 int rc = 0;
904 int bytes_returned;
905 int name_len;
906
907DelFileRetry:
908 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
909 (void **) &pSMBr);
910 if (rc)
911 return rc;
912
913 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
914 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000915 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700916 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 name_len++; /* trailing null */
918 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700919 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 name_len = strnlen(fileName, PATH_MAX);
921 name_len++; /* trailing null */
922 strncpy(pSMB->fileName, fileName, name_len);
923 }
924 pSMB->SearchAttributes =
925 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
926 pSMB->BufferFormat = 0x04;
927 pSMB->hdr.smb_buf_length += name_len + 1;
928 pSMB->ByteCount = cpu_to_le16(name_len + 1);
929 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
930 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700931 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 if (rc) {
933 cFYI(1, ("Error in RMFile = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
936 cifs_buf_release(pSMB);
937 if (rc == -EAGAIN)
938 goto DelFileRetry;
939
940 return rc;
941}
942
943int
Steve French50c2f752007-07-13 00:33:32 +0000944CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700945 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946{
947 DELETE_DIRECTORY_REQ *pSMB = NULL;
948 DELETE_DIRECTORY_RSP *pSMBr = NULL;
949 int rc = 0;
950 int bytes_returned;
951 int name_len;
952
953 cFYI(1, ("In CIFSSMBRmDir"));
954RmDirRetry:
955 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
956 (void **) &pSMBr);
957 if (rc)
958 return rc;
959
960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700961 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
962 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 name_len++; /* trailing null */
964 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700965 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 name_len = strnlen(dirName, PATH_MAX);
967 name_len++; /* trailing null */
968 strncpy(pSMB->DirName, dirName, name_len);
969 }
970
971 pSMB->BufferFormat = 0x04;
972 pSMB->hdr.smb_buf_length += name_len + 1;
973 pSMB->ByteCount = cpu_to_le16(name_len + 1);
974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700976 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 if (rc) {
978 cFYI(1, ("Error in RMDir = %d", rc));
979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981 cifs_buf_release(pSMB);
982 if (rc == -EAGAIN)
983 goto RmDirRetry;
984 return rc;
985}
986
987int
988CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700989 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
991 int rc = 0;
992 CREATE_DIRECTORY_REQ *pSMB = NULL;
993 CREATE_DIRECTORY_RSP *pSMBr = NULL;
994 int bytes_returned;
995 int name_len;
996
997 cFYI(1, ("In CIFSSMBMkDir"));
998MkDirRetry:
999 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1000 (void **) &pSMBr);
1001 if (rc)
1002 return rc;
1003
1004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00001005 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -07001006 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 name_len++; /* trailing null */
1008 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001009 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 name_len = strnlen(name, PATH_MAX);
1011 name_len++; /* trailing null */
1012 strncpy(pSMB->DirName, name, name_len);
1013 }
1014
1015 pSMB->BufferFormat = 0x04;
1016 pSMB->hdr.smb_buf_length += name_len + 1;
1017 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1019 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001020 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 if (rc) {
1022 cFYI(1, ("Error in Mkdir = %d", rc));
1023 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 cifs_buf_release(pSMB);
1026 if (rc == -EAGAIN)
1027 goto MkDirRetry;
1028 return rc;
1029}
1030
Steve French2dd29d32007-04-23 22:07:35 +00001031int
1032CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1033 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001034 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001035 const struct nls_table *nls_codepage, int remap)
1036{
1037 TRANSACTION2_SPI_REQ *pSMB = NULL;
1038 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1039 int name_len;
1040 int rc = 0;
1041 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001042 __u16 params, param_offset, offset, byte_count, count;
1043 OPEN_PSX_REQ * pdata;
1044 OPEN_PSX_RSP * psx_rsp;
1045
1046 cFYI(1, ("In POSIX Create"));
1047PsxCreat:
1048 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1049 (void **) &pSMBr);
1050 if (rc)
1051 return rc;
1052
1053 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1054 name_len =
1055 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1056 PATH_MAX, nls_codepage, remap);
1057 name_len++; /* trailing null */
1058 name_len *= 2;
1059 } else { /* BB improve the check for buffer overruns BB */
1060 name_len = strnlen(name, PATH_MAX);
1061 name_len++; /* trailing null */
1062 strncpy(pSMB->FileName, name, name_len);
1063 }
1064
1065 params = 6 + name_len;
1066 count = sizeof(OPEN_PSX_REQ);
1067 pSMB->MaxParameterCount = cpu_to_le16(2);
1068 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1069 pSMB->MaxSetupCount = 0;
1070 pSMB->Reserved = 0;
1071 pSMB->Flags = 0;
1072 pSMB->Timeout = 0;
1073 pSMB->Reserved2 = 0;
1074 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001075 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001076 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001077 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001078 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001079 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001080 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001081 pdata->OpenFlags = cpu_to_le32(*pOplock);
1082 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1083 pSMB->DataOffset = cpu_to_le16(offset);
1084 pSMB->SetupCount = 1;
1085 pSMB->Reserved3 = 0;
1086 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1087 byte_count = 3 /* pad */ + params + count;
1088
1089 pSMB->DataCount = cpu_to_le16(count);
1090 pSMB->ParameterCount = cpu_to_le16(params);
1091 pSMB->TotalDataCount = pSMB->DataCount;
1092 pSMB->TotalParameterCount = pSMB->ParameterCount;
1093 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1094 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001095 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001096 pSMB->ByteCount = cpu_to_le16(byte_count);
1097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1099 if (rc) {
1100 cFYI(1, ("Posix create returned %d", rc));
1101 goto psx_create_err;
1102 }
1103
Steve French790fe572007-07-07 19:25:05 +00001104 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001105 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1106
1107 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1108 rc = -EIO; /* bad smb */
1109 goto psx_create_err;
1110 }
1111
1112 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001113 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001114 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001115
Steve French2dd29d32007-04-23 22:07:35 +00001116 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001117 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001118 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1119 /* Let caller know file was created so we can set the mode. */
1120 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001121 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001122 *pOplock |= CIFS_CREATE_ACTION;
1123 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001124 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1125 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001126#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001127 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001128#endif
1129 } else {
Steve French790fe572007-07-07 19:25:05 +00001130 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001131 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001132 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001133 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001134 goto psx_create_err;
1135 }
Steve French50c2f752007-07-13 00:33:32 +00001136 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001137 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001138 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001139 }
Steve French2dd29d32007-04-23 22:07:35 +00001140
1141psx_create_err:
1142 cifs_buf_release(pSMB);
1143
1144 cifs_stats_inc(&tcon->num_mkdirs);
1145
1146 if (rc == -EAGAIN)
1147 goto PsxCreat;
1148
Steve French50c2f752007-07-13 00:33:32 +00001149 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001150}
1151
Steve Frencha9d02ad2005-08-24 23:06:05 -07001152static __u16 convert_disposition(int disposition)
1153{
1154 __u16 ofun = 0;
1155
1156 switch (disposition) {
1157 case FILE_SUPERSEDE:
1158 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1159 break;
1160 case FILE_OPEN:
1161 ofun = SMBOPEN_OAPPEND;
1162 break;
1163 case FILE_CREATE:
1164 ofun = SMBOPEN_OCREATE;
1165 break;
1166 case FILE_OPEN_IF:
1167 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1168 break;
1169 case FILE_OVERWRITE:
1170 ofun = SMBOPEN_OTRUNC;
1171 break;
1172 case FILE_OVERWRITE_IF:
1173 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1174 break;
1175 default:
Steve French790fe572007-07-07 19:25:05 +00001176 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001177 ofun = SMBOPEN_OAPPEND; /* regular open */
1178 }
1179 return ofun;
1180}
1181
1182int
1183SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1184 const char *fileName, const int openDisposition,
1185 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001186 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001187 const struct nls_table *nls_codepage, int remap)
1188{
1189 int rc = -EACCES;
1190 OPENX_REQ *pSMB = NULL;
1191 OPENX_RSP *pSMBr = NULL;
1192 int bytes_returned;
1193 int name_len;
1194 __u16 count;
1195
1196OldOpenRetry:
1197 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1198 (void **) &pSMBr);
1199 if (rc)
1200 return rc;
1201
1202 pSMB->AndXCommand = 0xFF; /* none */
1203
1204 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1205 count = 1; /* account for one byte pad to word boundary */
1206 name_len =
1207 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1208 fileName, PATH_MAX, nls_codepage, remap);
1209 name_len++; /* trailing null */
1210 name_len *= 2;
1211 } else { /* BB improve check for buffer overruns BB */
1212 count = 0; /* no pad */
1213 name_len = strnlen(fileName, PATH_MAX);
1214 name_len++; /* trailing null */
1215 strncpy(pSMB->fileName, fileName, name_len);
1216 }
1217 if (*pOplock & REQ_OPLOCK)
1218 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001219 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001221
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1223 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1224 /* 0 = read
1225 1 = write
1226 2 = rw
1227 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001228 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229 pSMB->Mode = cpu_to_le16(2);
1230 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1231 /* set file as system file if special file such
1232 as fifo and server expecting SFU style and
1233 no Unix extensions */
1234
Steve French790fe572007-07-07 19:25:05 +00001235 if (create_options & CREATE_OPTION_SPECIAL)
1236 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1237 else
Steve French3e87d802005-09-18 20:49:21 -07001238 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239
1240 /* if ((omode & S_IWUGO) == 0)
1241 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1242 /* Above line causes problems due to vfs splitting create into two
1243 pieces - need to set mode after file created not while it is
1244 being created */
1245
1246 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001247/* pSMB->CreateOptions = cpu_to_le32(create_options &
1248 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001250
1251 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001252 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 count += name_len;
1254 pSMB->hdr.smb_buf_length += count;
1255
1256 pSMB->ByteCount = cpu_to_le16(count);
1257 /* long_op set to 1 to allow for oplock break timeouts */
1258 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00001259 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 cifs_stats_inc(&tcon->num_opens);
1261 if (rc) {
1262 cFYI(1, ("Error in Open = %d", rc));
1263 } else {
1264 /* BB verify if wct == 15 */
1265
1266/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1267
1268 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1269 /* Let caller know file was created so we can set the mode. */
1270 /* Do we care about the CreateAction in any other cases? */
1271 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001272/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 *pOplock |= CIFS_CREATE_ACTION; */
1274 /* BB FIXME END */
1275
Steve French790fe572007-07-07 19:25:05 +00001276 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1278 pfile_info->LastAccessTime = 0; /* BB fixme */
1279 pfile_info->LastWriteTime = 0; /* BB fixme */
1280 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001281 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001282 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001283 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001284 pfile_info->AllocationSize =
1285 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1286 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001287 pfile_info->NumberOfLinks = cpu_to_le32(1);
1288 }
1289 }
1290
1291 cifs_buf_release(pSMB);
1292 if (rc == -EAGAIN)
1293 goto OldOpenRetry;
1294 return rc;
1295}
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297int
1298CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1299 const char *fileName, const int openDisposition,
1300 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001301 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001302 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303{
1304 int rc = -EACCES;
1305 OPEN_REQ *pSMB = NULL;
1306 OPEN_RSP *pSMBr = NULL;
1307 int bytes_returned;
1308 int name_len;
1309 __u16 count;
1310
1311openRetry:
1312 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1313 (void **) &pSMBr);
1314 if (rc)
1315 return rc;
1316
1317 pSMB->AndXCommand = 0xFF; /* none */
1318
1319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1320 count = 1; /* account for one byte pad to word boundary */
1321 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001322 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001323 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 name_len++; /* trailing null */
1325 name_len *= 2;
1326 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001327 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 count = 0; /* no pad */
1329 name_len = strnlen(fileName, PATH_MAX);
1330 name_len++; /* trailing null */
1331 pSMB->NameLength = cpu_to_le16(name_len);
1332 strncpy(pSMB->fileName, fileName, name_len);
1333 }
1334 if (*pOplock & REQ_OPLOCK)
1335 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001336 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1339 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001340 /* set file as system file if special file such
1341 as fifo and server expecting SFU style and
1342 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001343 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001344 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1345 else
1346 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 /* XP does not handle ATTR_POSIX_SEMANTICS */
1348 /* but it helps speed up case sensitive checks for other
1349 servers such as Samba */
1350 if (tcon->ses->capabilities & CAP_UNIX)
1351 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1352
1353 /* if ((omode & S_IWUGO) == 0)
1354 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1355 /* Above line causes problems due to vfs splitting create into two
1356 pieces - need to set mode after file created not while it is
1357 being created */
1358 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1359 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001360 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001361 /* BB Expirement with various impersonation levels and verify */
1362 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 pSMB->SecurityFlags =
1364 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1365
1366 count += name_len;
1367 pSMB->hdr.smb_buf_length += count;
1368
1369 pSMB->ByteCount = cpu_to_le16(count);
1370 /* long_op set to 1 to allow for oplock break timeouts */
1371 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1372 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001373 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 if (rc) {
1375 cFYI(1, ("Error in Open = %d", rc));
1376 } else {
Steve French09d1db52005-04-28 22:41:08 -07001377 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1379 /* Let caller know file was created so we can set the mode. */
1380 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001381 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001382 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001383 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001384 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 36 /* CreationTime to Attributes */);
1386 /* the file_info buf is endian converted by caller */
1387 pfile_info->AllocationSize = pSMBr->AllocationSize;
1388 pfile_info->EndOfFile = pSMBr->EndOfFile;
1389 pfile_info->NumberOfLinks = cpu_to_le32(1);
1390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 cifs_buf_release(pSMB);
1394 if (rc == -EAGAIN)
1395 goto openRetry;
1396 return rc;
1397}
1398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399int
Steve French50c2f752007-07-13 00:33:32 +00001400CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1401 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1402 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403{
1404 int rc = -EACCES;
1405 READ_REQ *pSMB = NULL;
1406 READ_RSP *pSMBr = NULL;
1407 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001408 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001409 int resp_buf_type = 0;
1410 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Steve French790fe572007-07-07 19:25:05 +00001412 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1413 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001414 wct = 12;
1415 else
1416 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
1418 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001419 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 if (rc)
1421 return rc;
1422
1423 /* tcon and ses pointer are checked in smb_init */
1424 if (tcon->ses->server == NULL)
1425 return -ECONNABORTED;
1426
Steve Frenchec637e32005-12-12 20:53:18 -08001427 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 pSMB->Fid = netfid;
1429 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001430 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001431 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001432 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001433 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 pSMB->Remaining = 0;
1436 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1437 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001438 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001439 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1440 else {
1441 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001442 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001443 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001444 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001445 }
Steve Frenchec637e32005-12-12 20:53:18 -08001446
1447 iov[0].iov_base = (char *)pSMB;
1448 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001449 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1450 &resp_buf_type, 0 /* not long op */, 1 /* log err */ );
Steve Frencha4544342005-08-24 13:59:35 -07001451 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001452 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 if (rc) {
1454 cERROR(1, ("Send error in read = %d", rc));
1455 } else {
1456 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1457 data_length = data_length << 16;
1458 data_length += le16_to_cpu(pSMBr->DataLength);
1459 *nbytes = data_length;
1460
1461 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001462 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001464 cFYI(1, ("bad length %d for count %d",
1465 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 rc = -EIO;
1467 *nbytes = 0;
1468 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001469 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001470 le16_to_cpu(pSMBr->DataOffset);
1471/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001472 cERROR(1,("Faulting on read rc = %d",rc));
1473 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001474 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001475 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001476 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 }
1478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
Steve French4b8f9302006-02-26 16:41:18 +00001480/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001481 if (*buf) {
1482 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001483 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001484 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001485 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001486 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001487 /* return buffer to caller to free */
1488 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001489 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001490 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001491 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001492 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001493 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001494
1495 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 since file handle passed in no longer valid */
1497 return rc;
1498}
1499
Steve Frenchec637e32005-12-12 20:53:18 -08001500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501int
1502CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1503 const int netfid, const unsigned int count,
1504 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001505 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
1507 int rc = -EACCES;
1508 WRITE_REQ *pSMB = NULL;
1509 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001510 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 __u32 bytes_sent;
1512 __u16 byte_count;
1513
1514 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001515 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001516 return -ECONNABORTED;
1517
Steve French790fe572007-07-07 19:25:05 +00001518 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001519 wct = 14;
1520 else
1521 wct = 12;
1522
1523 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 (void **) &pSMBr);
1525 if (rc)
1526 return rc;
1527 /* tcon and ses pointer are checked in smb_init */
1528 if (tcon->ses->server == NULL)
1529 return -ECONNABORTED;
1530
1531 pSMB->AndXCommand = 0xFF; /* none */
1532 pSMB->Fid = netfid;
1533 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001534 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001535 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001536 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001537 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001538
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 pSMB->Reserved = 0xFFFFFFFF;
1540 pSMB->WriteMode = 0;
1541 pSMB->Remaining = 0;
1542
Steve French50c2f752007-07-13 00:33:32 +00001543 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 can send more if LARGE_WRITE_X capability returned by the server and if
1545 our buffer is big enough or if we convert to iovecs on socket writes
1546 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001547 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1549 } else {
1550 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1551 & ~0xFF;
1552 }
1553
1554 if (bytes_sent > count)
1555 bytes_sent = count;
1556 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001557 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001558 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001559 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001560 else if (ubuf) {
1561 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 cifs_buf_release(pSMB);
1563 return -EFAULT;
1564 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001565 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 /* No buffer */
1567 cifs_buf_release(pSMB);
1568 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001569 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001570 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001571 byte_count = bytes_sent + 1; /* pad */
1572 else /* wct == 12 */ {
1573 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1576 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001577 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001578
Steve French790fe572007-07-07 19:25:05 +00001579 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001580 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001581 else { /* old style write has byte count 4 bytes earlier
1582 so 4 bytes pad */
1583 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001584 (struct smb_com_writex_req *)pSMB;
1585 pSMBW->ByteCount = cpu_to_le16(byte_count);
1586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
1588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1589 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001590 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 if (rc) {
1592 cFYI(1, ("Send error in write = %d", rc));
1593 *nbytes = 0;
1594 } else {
1595 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1596 *nbytes = (*nbytes) << 16;
1597 *nbytes += le16_to_cpu(pSMBr->Count);
1598 }
1599
1600 cifs_buf_release(pSMB);
1601
Steve French50c2f752007-07-13 00:33:32 +00001602 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 since file handle passed in no longer valid */
1604
1605 return rc;
1606}
1607
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001608int
1609CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001611 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1612 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613{
1614 int rc = -EACCES;
1615 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001616 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001617 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001618 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
Steve French790fe572007-07-07 19:25:05 +00001620 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001621
Steve French790fe572007-07-07 19:25:05 +00001622 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001623 wct = 14;
1624 else
1625 wct = 12;
1626 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 if (rc)
1628 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 /* tcon and ses pointer are checked in smb_init */
1630 if (tcon->ses->server == NULL)
1631 return -ECONNABORTED;
1632
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001633 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 pSMB->Fid = netfid;
1635 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001636 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001637 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001638 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001639 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 pSMB->Reserved = 0xFFFFFFFF;
1641 pSMB->WriteMode = 0;
1642 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001645 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
Steve French3e844692005-10-03 13:37:24 -07001647 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1648 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001649 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001650 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001651 pSMB->hdr.smb_buf_length += count+1;
1652 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001653 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1654 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001655 pSMB->ByteCount = cpu_to_le16(count + 1);
1656 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001657 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001658 (struct smb_com_writex_req *)pSMB;
1659 pSMBW->ByteCount = cpu_to_le16(count + 5);
1660 }
Steve French3e844692005-10-03 13:37:24 -07001661 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001662 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001663 iov[0].iov_len = smb_hdr_len + 4;
1664 else /* wct == 12 pad bigger by four bytes */
1665 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001666
Steve French3e844692005-10-03 13:37:24 -07001667
Steve Frenchec637e32005-12-12 20:53:18 -08001668 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve Frencha761ac52007-10-18 21:45:27 +00001669 long_op, 0 /* do not log STATUS code */ );
Steve Frencha4544342005-08-24 13:59:35 -07001670 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001672 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001674 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001675 /* presumably this can not happen, but best to be safe */
1676 rc = -EIO;
1677 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001678 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001679 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001680 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1681 *nbytes = (*nbytes) << 16;
1682 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Steve French4b8f9302006-02-26 16:41:18 +00001685/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001686 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001687 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001688 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001689 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Steve French50c2f752007-07-13 00:33:32 +00001691 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 since file handle passed in no longer valid */
1693
1694 return rc;
1695}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001696
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698int
1699CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1700 const __u16 smb_file_id, const __u64 len,
1701 const __u64 offset, const __u32 numUnlock,
1702 const __u32 numLock, const __u8 lockType, const int waitFlag)
1703{
1704 int rc = 0;
1705 LOCK_REQ *pSMB = NULL;
1706 LOCK_RSP *pSMBr = NULL;
1707 int bytes_returned;
1708 int timeout = 0;
1709 __u16 count;
1710
Steve French50c2f752007-07-13 00:33:32 +00001711 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001712 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1713
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 if (rc)
1715 return rc;
1716
Steve French46810cb2005-04-28 22:41:09 -07001717 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1718
Steve French790fe572007-07-07 19:25:05 +00001719 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 timeout = -1; /* no response expected */
1721 pSMB->Timeout = 0;
1722 } else if (waitFlag == TRUE) {
1723 timeout = 3; /* blocking operation, no timeout */
1724 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1725 } else {
1726 pSMB->Timeout = 0;
1727 }
1728
1729 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1730 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1731 pSMB->LockType = lockType;
1732 pSMB->AndXCommand = 0xFF; /* none */
1733 pSMB->Fid = smb_file_id; /* netfid stays le */
1734
Steve French790fe572007-07-07 19:25:05 +00001735 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1737 /* BB where to store pid high? */
1738 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1739 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1740 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1741 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1742 count = sizeof(LOCKING_ANDX_RANGE);
1743 } else {
1744 /* oplock break */
1745 count = 0;
1746 }
1747 pSMB->hdr.smb_buf_length += count;
1748 pSMB->ByteCount = cpu_to_le16(count);
1749
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001750 if (waitFlag) {
1751 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1752 (struct smb_hdr *) pSMBr, &bytes_returned);
1753 } else {
1754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001756 }
Steve Frencha4544342005-08-24 13:59:35 -07001757 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (rc) {
1759 cFYI(1, ("Send error in Lock = %d", rc));
1760 }
Steve French46810cb2005-04-28 22:41:09 -07001761 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762
Steve French50c2f752007-07-13 00:33:32 +00001763 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 since file handle passed in no longer valid */
1765 return rc;
1766}
1767
1768int
Steve French08547b02006-02-28 22:39:25 +00001769CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1770 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001771 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001772 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001773{
1774 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1775 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001776 struct cifs_posix_lock *parm_data;
1777 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001778 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001779 int bytes_returned = 0;
1780 __u16 params, param_offset, offset, byte_count, count;
1781
1782 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001783
Steve French790fe572007-07-07 19:25:05 +00001784 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001785 return EINVAL;
1786
Steve French08547b02006-02-28 22:39:25 +00001787 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1788
1789 if (rc)
1790 return rc;
1791
1792 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1793
Steve French50c2f752007-07-13 00:33:32 +00001794 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001795 pSMB->MaxSetupCount = 0;
1796 pSMB->Reserved = 0;
1797 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001798 pSMB->Reserved2 = 0;
1799 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1800 offset = param_offset + params;
1801
Steve French08547b02006-02-28 22:39:25 +00001802 count = sizeof(struct cifs_posix_lock);
1803 pSMB->MaxParameterCount = cpu_to_le16(2);
1804 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1805 pSMB->SetupCount = 1;
1806 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001807 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001808 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1809 else
1810 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1811 byte_count = 3 /* pad */ + params + count;
1812 pSMB->DataCount = cpu_to_le16(count);
1813 pSMB->ParameterCount = cpu_to_le16(params);
1814 pSMB->TotalDataCount = pSMB->DataCount;
1815 pSMB->TotalParameterCount = pSMB->ParameterCount;
1816 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001817 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001818 (((char *) &pSMB->hdr.Protocol) + offset);
1819
1820 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001821 if (waitFlag) {
Steve French3a5ff612006-07-14 22:37:11 +00001822 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001823 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001824 pSMB->Timeout = cpu_to_le32(-1);
1825 } else
1826 pSMB->Timeout = 0;
1827
Steve French08547b02006-02-28 22:39:25 +00001828 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001829 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001830 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001831
1832 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001833 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001834 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1835 pSMB->Reserved4 = 0;
1836 pSMB->hdr.smb_buf_length += byte_count;
1837 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001838 if (waitFlag) {
1839 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1840 (struct smb_hdr *) pSMBr, &bytes_returned);
1841 } else {
1842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001843 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001844 }
1845
Steve French08547b02006-02-28 22:39:25 +00001846 if (rc) {
1847 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001848 } else if (get_flag) {
1849 /* lock structure can be returned on get */
1850 __u16 data_offset;
1851 __u16 data_count;
1852 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001853
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001854 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1855 rc = -EIO; /* bad smb */
1856 goto plk_err_exit;
1857 }
Steve French790fe572007-07-07 19:25:05 +00001858 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001859 rc = -EINVAL;
1860 goto plk_err_exit;
1861 }
1862 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1863 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001864 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001865 rc = -EIO;
1866 goto plk_err_exit;
1867 }
1868 parm_data = (struct cifs_posix_lock *)
1869 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001870 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001871 pLockData->fl_type = F_UNLCK;
1872 }
Steve French50c2f752007-07-13 00:33:32 +00001873
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001874plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001875 if (pSMB)
1876 cifs_small_buf_release(pSMB);
1877
1878 /* Note: On -EAGAIN error only caller can retry on handle based calls
1879 since file handle passed in no longer valid */
1880
1881 return rc;
1882}
1883
1884
1885int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1887{
1888 int rc = 0;
1889 CLOSE_REQ *pSMB = NULL;
1890 CLOSE_RSP *pSMBr = NULL;
1891 int bytes_returned;
1892 cFYI(1, ("In CIFSSMBClose"));
1893
1894/* do not retry on dead session on close */
1895 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001896 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 return 0;
1898 if (rc)
1899 return rc;
1900
1901 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1902
1903 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001904 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 pSMB->ByteCount = 0;
1906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001908 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001910 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 /* EINTR is expected when user ctl-c to kill app */
1912 cERROR(1, ("Send error in Close = %d", rc));
1913 }
1914 }
1915
1916 cifs_small_buf_release(pSMB);
1917
1918 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001919 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 rc = 0;
1921
1922 return rc;
1923}
1924
1925int
1926CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1927 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001928 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929{
1930 int rc = 0;
1931 RENAME_REQ *pSMB = NULL;
1932 RENAME_RSP *pSMBr = NULL;
1933 int bytes_returned;
1934 int name_len, name_len2;
1935 __u16 count;
1936
1937 cFYI(1, ("In CIFSSMBRename"));
1938renameRetry:
1939 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1940 (void **) &pSMBr);
1941 if (rc)
1942 return rc;
1943
1944 pSMB->BufferFormat = 0x04;
1945 pSMB->SearchAttributes =
1946 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1947 ATTR_DIRECTORY);
1948
1949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1950 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001951 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001952 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 name_len++; /* trailing null */
1954 name_len *= 2;
1955 pSMB->OldFileName[name_len] = 0x04; /* pad */
1956 /* protocol requires ASCII signature byte on Unicode string */
1957 pSMB->OldFileName[name_len + 1] = 0x00;
1958 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001959 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001960 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1962 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001963 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 name_len = strnlen(fromName, PATH_MAX);
1965 name_len++; /* trailing null */
1966 strncpy(pSMB->OldFileName, fromName, name_len);
1967 name_len2 = strnlen(toName, PATH_MAX);
1968 name_len2++; /* trailing null */
1969 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1970 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1971 name_len2++; /* trailing null */
1972 name_len2++; /* signature byte */
1973 }
1974
1975 count = 1 /* 1st signature byte */ + name_len + name_len2;
1976 pSMB->hdr.smb_buf_length += count;
1977 pSMB->ByteCount = cpu_to_le16(count);
1978
1979 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1980 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001981 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 if (rc) {
1983 cFYI(1, ("Send error in rename = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +00001984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 cifs_buf_release(pSMB);
1987
1988 if (rc == -EAGAIN)
1989 goto renameRetry;
1990
1991 return rc;
1992}
1993
Steve French50c2f752007-07-13 00:33:32 +00001994int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1995 int netfid, char *target_name,
1996 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997{
1998 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1999 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002000 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 char *data_offset;
2002 char dummy_string[30];
2003 int rc = 0;
2004 int bytes_returned = 0;
2005 int len_of_str;
2006 __u16 params, param_offset, offset, count, byte_count;
2007
2008 cFYI(1, ("Rename to File by handle"));
2009 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2010 (void **) &pSMBr);
2011 if (rc)
2012 return rc;
2013
2014 params = 6;
2015 pSMB->MaxSetupCount = 0;
2016 pSMB->Reserved = 0;
2017 pSMB->Flags = 0;
2018 pSMB->Timeout = 0;
2019 pSMB->Reserved2 = 0;
2020 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2021 offset = param_offset + params;
2022
2023 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2024 rename_info = (struct set_file_rename *) data_offset;
2025 pSMB->MaxParameterCount = cpu_to_le16(2);
2026 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2027 pSMB->SetupCount = 1;
2028 pSMB->Reserved3 = 0;
2029 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2030 byte_count = 3 /* pad */ + params;
2031 pSMB->ParameterCount = cpu_to_le16(params);
2032 pSMB->TotalParameterCount = pSMB->ParameterCount;
2033 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2034 pSMB->DataOffset = cpu_to_le16(offset);
2035 /* construct random name ".cifs_tmp<inodenum><mid>" */
2036 rename_info->overwrite = cpu_to_le32(1);
2037 rename_info->root_fid = 0;
2038 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002039 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002040 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2041 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002042 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002044 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002045 target_name, PATH_MAX, nls_codepage,
2046 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 }
2048 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2049 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2050 byte_count += count;
2051 pSMB->DataCount = cpu_to_le16(count);
2052 pSMB->TotalDataCount = pSMB->DataCount;
2053 pSMB->Fid = netfid;
2054 pSMB->InformationLevel =
2055 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2056 pSMB->Reserved4 = 0;
2057 pSMB->hdr.smb_buf_length += byte_count;
2058 pSMB->ByteCount = cpu_to_le16(byte_count);
2059 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002060 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002061 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002063 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 }
Steve Frencha5a2b482005-08-20 21:42:53 -07002065
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 cifs_buf_release(pSMB);
2067
2068 /* Note: On -EAGAIN error only caller can retry on handle based calls
2069 since file handle passed in no longer valid */
2070
2071 return rc;
2072}
2073
2074int
Steve French50c2f752007-07-13 00:33:32 +00002075CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2076 const __u16 target_tid, const char *toName, const int flags,
2077 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078{
2079 int rc = 0;
2080 COPY_REQ *pSMB = NULL;
2081 COPY_RSP *pSMBr = NULL;
2082 int bytes_returned;
2083 int name_len, name_len2;
2084 __u16 count;
2085
2086 cFYI(1, ("In CIFSSMBCopy"));
2087copyRetry:
2088 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2089 (void **) &pSMBr);
2090 if (rc)
2091 return rc;
2092
2093 pSMB->BufferFormat = 0x04;
2094 pSMB->Tid2 = target_tid;
2095
2096 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2097
2098 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002099 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002100 fromName, PATH_MAX, nls_codepage,
2101 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 name_len++; /* trailing null */
2103 name_len *= 2;
2104 pSMB->OldFileName[name_len] = 0x04; /* pad */
2105 /* protocol requires ASCII signature byte on Unicode string */
2106 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002107 name_len2 =
2108 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002109 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2111 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002112 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 name_len = strnlen(fromName, PATH_MAX);
2114 name_len++; /* trailing null */
2115 strncpy(pSMB->OldFileName, fromName, name_len);
2116 name_len2 = strnlen(toName, PATH_MAX);
2117 name_len2++; /* trailing null */
2118 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2119 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2120 name_len2++; /* trailing null */
2121 name_len2++; /* signature byte */
2122 }
2123
2124 count = 1 /* 1st signature byte */ + name_len + name_len2;
2125 pSMB->hdr.smb_buf_length += count;
2126 pSMB->ByteCount = cpu_to_le16(count);
2127
2128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2129 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2130 if (rc) {
2131 cFYI(1, ("Send error in copy = %d with %d files copied",
2132 rc, le16_to_cpu(pSMBr->CopyCount)));
2133 }
2134 if (pSMB)
2135 cifs_buf_release(pSMB);
2136
2137 if (rc == -EAGAIN)
2138 goto copyRetry;
2139
2140 return rc;
2141}
2142
2143int
2144CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2145 const char *fromName, const char *toName,
2146 const struct nls_table *nls_codepage)
2147{
2148 TRANSACTION2_SPI_REQ *pSMB = NULL;
2149 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2150 char *data_offset;
2151 int name_len;
2152 int name_len_target;
2153 int rc = 0;
2154 int bytes_returned = 0;
2155 __u16 params, param_offset, offset, byte_count;
2156
2157 cFYI(1, ("In Symlink Unix style"));
2158createSymLinkRetry:
2159 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2160 (void **) &pSMBr);
2161 if (rc)
2162 return rc;
2163
2164 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2165 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002166 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 /* find define for this maxpathcomponent */
2168 , nls_codepage);
2169 name_len++; /* trailing null */
2170 name_len *= 2;
2171
Steve French50c2f752007-07-13 00:33:32 +00002172 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 name_len = strnlen(fromName, PATH_MAX);
2174 name_len++; /* trailing null */
2175 strncpy(pSMB->FileName, fromName, name_len);
2176 }
2177 params = 6 + name_len;
2178 pSMB->MaxSetupCount = 0;
2179 pSMB->Reserved = 0;
2180 pSMB->Flags = 0;
2181 pSMB->Timeout = 0;
2182 pSMB->Reserved2 = 0;
2183 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002184 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 offset = param_offset + params;
2186
2187 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2188 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2189 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002190 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 /* find define for this maxpathcomponent */
2192 , nls_codepage);
2193 name_len_target++; /* trailing null */
2194 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002195 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 name_len_target = strnlen(toName, PATH_MAX);
2197 name_len_target++; /* trailing null */
2198 strncpy(data_offset, toName, name_len_target);
2199 }
2200
2201 pSMB->MaxParameterCount = cpu_to_le16(2);
2202 /* BB find exact max on data count below from sess */
2203 pSMB->MaxDataCount = cpu_to_le16(1000);
2204 pSMB->SetupCount = 1;
2205 pSMB->Reserved3 = 0;
2206 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2207 byte_count = 3 /* pad */ + params + name_len_target;
2208 pSMB->DataCount = cpu_to_le16(name_len_target);
2209 pSMB->ParameterCount = cpu_to_le16(params);
2210 pSMB->TotalDataCount = pSMB->DataCount;
2211 pSMB->TotalParameterCount = pSMB->ParameterCount;
2212 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2213 pSMB->DataOffset = cpu_to_le16(offset);
2214 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2215 pSMB->Reserved4 = 0;
2216 pSMB->hdr.smb_buf_length += byte_count;
2217 pSMB->ByteCount = cpu_to_le16(byte_count);
2218 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2219 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002220 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 if (rc) {
Steve French2d785a52007-07-15 01:48:57 +00002222 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 }
2224
2225 if (pSMB)
2226 cifs_buf_release(pSMB);
2227
2228 if (rc == -EAGAIN)
2229 goto createSymLinkRetry;
2230
2231 return rc;
2232}
2233
2234int
2235CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2236 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002237 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238{
2239 TRANSACTION2_SPI_REQ *pSMB = NULL;
2240 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2241 char *data_offset;
2242 int name_len;
2243 int name_len_target;
2244 int rc = 0;
2245 int bytes_returned = 0;
2246 __u16 params, param_offset, offset, byte_count;
2247
2248 cFYI(1, ("In Create Hard link Unix style"));
2249createHardLinkRetry:
2250 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2251 (void **) &pSMBr);
2252 if (rc)
2253 return rc;
2254
2255 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002256 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002257 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 name_len++; /* trailing null */
2259 name_len *= 2;
2260
Steve French50c2f752007-07-13 00:33:32 +00002261 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 name_len = strnlen(toName, PATH_MAX);
2263 name_len++; /* trailing null */
2264 strncpy(pSMB->FileName, toName, name_len);
2265 }
2266 params = 6 + name_len;
2267 pSMB->MaxSetupCount = 0;
2268 pSMB->Reserved = 0;
2269 pSMB->Flags = 0;
2270 pSMB->Timeout = 0;
2271 pSMB->Reserved2 = 0;
2272 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002273 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 offset = param_offset + params;
2275
2276 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2277 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2278 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002279 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002280 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 name_len_target++; /* trailing null */
2282 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002283 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 name_len_target = strnlen(fromName, PATH_MAX);
2285 name_len_target++; /* trailing null */
2286 strncpy(data_offset, fromName, name_len_target);
2287 }
2288
2289 pSMB->MaxParameterCount = cpu_to_le16(2);
2290 /* BB find exact max on data count below from sess*/
2291 pSMB->MaxDataCount = cpu_to_le16(1000);
2292 pSMB->SetupCount = 1;
2293 pSMB->Reserved3 = 0;
2294 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2295 byte_count = 3 /* pad */ + params + name_len_target;
2296 pSMB->ParameterCount = cpu_to_le16(params);
2297 pSMB->TotalParameterCount = pSMB->ParameterCount;
2298 pSMB->DataCount = cpu_to_le16(name_len_target);
2299 pSMB->TotalDataCount = pSMB->DataCount;
2300 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2301 pSMB->DataOffset = cpu_to_le16(offset);
2302 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2303 pSMB->Reserved4 = 0;
2304 pSMB->hdr.smb_buf_length += byte_count;
2305 pSMB->ByteCount = cpu_to_le16(byte_count);
2306 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2307 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002308 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 if (rc) {
2310 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2311 }
2312
2313 cifs_buf_release(pSMB);
2314 if (rc == -EAGAIN)
2315 goto createHardLinkRetry;
2316
2317 return rc;
2318}
2319
2320int
2321CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2322 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002323 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324{
2325 int rc = 0;
2326 NT_RENAME_REQ *pSMB = NULL;
2327 RENAME_RSP *pSMBr = NULL;
2328 int bytes_returned;
2329 int name_len, name_len2;
2330 __u16 count;
2331
2332 cFYI(1, ("In CIFSCreateHardLink"));
2333winCreateHardLinkRetry:
2334
2335 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2336 (void **) &pSMBr);
2337 if (rc)
2338 return rc;
2339
2340 pSMB->SearchAttributes =
2341 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2342 ATTR_DIRECTORY);
2343 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2344 pSMB->ClusterCount = 0;
2345
2346 pSMB->BufferFormat = 0x04;
2347
2348 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2349 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002350 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002351 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 name_len++; /* trailing null */
2353 name_len *= 2;
2354 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002355 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002357 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002358 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2360 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002361 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 name_len = strnlen(fromName, PATH_MAX);
2363 name_len++; /* trailing null */
2364 strncpy(pSMB->OldFileName, fromName, name_len);
2365 name_len2 = strnlen(toName, PATH_MAX);
2366 name_len2++; /* trailing null */
2367 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2368 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2369 name_len2++; /* trailing null */
2370 name_len2++; /* signature byte */
2371 }
2372
2373 count = 1 /* string type byte */ + name_len + name_len2;
2374 pSMB->hdr.smb_buf_length += count;
2375 pSMB->ByteCount = cpu_to_le16(count);
2376
2377 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2378 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002379 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 if (rc) {
2381 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2382 }
2383 cifs_buf_release(pSMB);
2384 if (rc == -EAGAIN)
2385 goto winCreateHardLinkRetry;
2386
2387 return rc;
2388}
2389
2390int
2391CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2392 const unsigned char *searchName,
2393 char *symlinkinfo, const int buflen,
2394 const struct nls_table *nls_codepage)
2395{
2396/* SMB_QUERY_FILE_UNIX_LINK */
2397 TRANSACTION2_QPI_REQ *pSMB = NULL;
2398 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2399 int rc = 0;
2400 int bytes_returned;
2401 int name_len;
2402 __u16 params, byte_count;
2403
2404 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2405
2406querySymLinkRetry:
2407 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2408 (void **) &pSMBr);
2409 if (rc)
2410 return rc;
2411
2412 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2413 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002414 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2415 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 name_len++; /* trailing null */
2417 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002418 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 name_len = strnlen(searchName, PATH_MAX);
2420 name_len++; /* trailing null */
2421 strncpy(pSMB->FileName, searchName, name_len);
2422 }
2423
2424 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2425 pSMB->TotalDataCount = 0;
2426 pSMB->MaxParameterCount = cpu_to_le16(2);
2427 /* BB find exact max data count below from sess structure BB */
2428 pSMB->MaxDataCount = cpu_to_le16(4000);
2429 pSMB->MaxSetupCount = 0;
2430 pSMB->Reserved = 0;
2431 pSMB->Flags = 0;
2432 pSMB->Timeout = 0;
2433 pSMB->Reserved2 = 0;
2434 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002435 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 pSMB->DataCount = 0;
2437 pSMB->DataOffset = 0;
2438 pSMB->SetupCount = 1;
2439 pSMB->Reserved3 = 0;
2440 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2441 byte_count = params + 1 /* pad */ ;
2442 pSMB->TotalParameterCount = cpu_to_le16(params);
2443 pSMB->ParameterCount = pSMB->TotalParameterCount;
2444 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2445 pSMB->Reserved4 = 0;
2446 pSMB->hdr.smb_buf_length += byte_count;
2447 pSMB->ByteCount = cpu_to_le16(byte_count);
2448
2449 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2450 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2451 if (rc) {
2452 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2453 } else {
2454 /* decode response */
2455
2456 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2457 if (rc || (pSMBr->ByteCount < 2))
2458 /* BB also check enough total bytes returned */
2459 rc = -EIO; /* bad smb */
2460 else {
2461 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2462 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2463
2464 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2465 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002466 &pSMBr->hdr.Protocol + data_offset),
2467 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002468 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002470 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2471 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 name_len, nls_codepage);
2473 } else {
2474 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002475 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 data_offset,
2477 min_t(const int, buflen, count));
2478 }
2479 symlinkinfo[buflen] = 0;
2480 /* just in case so calling code does not go off the end of buffer */
2481 }
2482 }
2483 cifs_buf_release(pSMB);
2484 if (rc == -EAGAIN)
2485 goto querySymLinkRetry;
2486 return rc;
2487}
2488
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 Frenchb9c7a2b2007-10-26 23:40:20 +00002498smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002499 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,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002529 __u32 *pparmlen, __u32 *pdatalen)
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 French630f3f02007-10-25 21:17:17 +00002535 *pdatalen = 0;
2536 *pparmlen = 0;
2537
Steve French790fe572007-07-07 19:25:05 +00002538 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002539 return -EINVAL;
2540
2541 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2542
2543 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002544 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002545 (char *)&pSMBr->ByteCount;
2546
Steve French0a4b92c2006-01-12 15:44:21 -08002547 data_offset = le32_to_cpu(pSMBr->DataOffset);
2548 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002549 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002550 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2551
2552 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2553 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2554
2555 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002556 if (*ppparm > end_of_smb) {
2557 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002558 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002559 } else if (parm_count + *ppparm > end_of_smb) {
2560 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002561 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002562 } else if (*ppdata > end_of_smb) {
2563 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002564 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002565 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002566 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002567 *ppdata, data_count, (data_count + *ppdata),
2568 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002569 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002570 } else if (parm_count + data_count > pSMBr->ByteCount) {
2571 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002572 return -EINVAL;
2573 }
Steve French630f3f02007-10-25 21:17:17 +00002574 *pdatalen = data_count;
2575 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002576 return 0;
2577}
Parag Warudkarc9489772007-10-23 18:09:48 +00002578#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002579
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580int
2581CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2582 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002583 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 const struct nls_table *nls_codepage)
2585{
2586 int rc = 0;
2587 int bytes_returned;
2588 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002589 struct smb_com_transaction_ioctl_req *pSMB;
2590 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591
2592 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2593 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2594 (void **) &pSMBr);
2595 if (rc)
2596 return rc;
2597
2598 pSMB->TotalParameterCount = 0 ;
2599 pSMB->TotalDataCount = 0;
2600 pSMB->MaxParameterCount = cpu_to_le32(2);
2601 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002602 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2603 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 pSMB->MaxSetupCount = 4;
2605 pSMB->Reserved = 0;
2606 pSMB->ParameterOffset = 0;
2607 pSMB->DataCount = 0;
2608 pSMB->DataOffset = 0;
2609 pSMB->SetupCount = 4;
2610 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2611 pSMB->ParameterCount = pSMB->TotalParameterCount;
2612 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2613 pSMB->IsFsctl = 1; /* FSCTL */
2614 pSMB->IsRootFlag = 0;
2615 pSMB->Fid = fid; /* file handle always le */
2616 pSMB->ByteCount = 0;
2617
2618 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2619 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2620 if (rc) {
2621 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2622 } else { /* decode response */
2623 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2624 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2625 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2626 /* BB also check enough total bytes returned */
2627 rc = -EIO; /* bad smb */
2628 else {
Steve French790fe572007-07-07 19:25:05 +00002629 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002630 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002631 pSMBr->ByteCount +
2632 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633
Steve French50c2f752007-07-13 00:33:32 +00002634 struct reparse_data *reparse_buf =
2635 (struct reparse_data *)
2636 ((char *)&pSMBr->hdr.Protocol
2637 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002638 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 rc = -EIO;
2640 goto qreparse_out;
2641 }
Steve French790fe572007-07-07 19:25:05 +00002642 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 reparse_buf->TargetNameOffset +
2644 reparse_buf->TargetNameLen) >
2645 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002646 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 rc = -EIO;
2648 goto qreparse_out;
2649 }
Steve French50c2f752007-07-13 00:33:32 +00002650
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2652 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002653 (reparse_buf->LinkNamesBuf +
2654 reparse_buf->TargetNameOffset),
2655 min(buflen/2,
2656 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002658 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 reparse_buf->TargetNameOffset),
2660 name_len, nls_codepage);
2661 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002662 strncpy(symlinkinfo,
2663 reparse_buf->LinkNamesBuf +
2664 reparse_buf->TargetNameOffset,
2665 min_t(const int, buflen,
2666 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 }
2668 } else {
2669 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002670 cFYI(1, ("Invalid return data count on "
2671 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 }
2673 symlinkinfo[buflen] = 0; /* just in case so the caller
2674 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002675 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 }
2677 }
2678qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002679 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680
2681 /* Note: On -EAGAIN error only caller can retry on handle based calls
2682 since file handle passed in no longer valid */
2683
2684 return rc;
2685}
2686
2687#ifdef CONFIG_CIFS_POSIX
2688
2689/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002690static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2691 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692{
2693 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002694 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2695 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2696 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2698
2699 return;
2700}
2701
2702/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002703static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2704 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705{
2706 int size = 0;
2707 int i;
2708 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002709 struct cifs_posix_ace *pACE;
2710 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2711 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
2713 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2714 return -EOPNOTSUPP;
2715
Steve French790fe572007-07-07 19:25:05 +00002716 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 count = le16_to_cpu(cifs_acl->access_entry_count);
2718 pACE = &cifs_acl->ace_array[0];
2719 size = sizeof(struct cifs_posix_acl);
2720 size += sizeof(struct cifs_posix_ace) * count;
2721 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002722 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002723 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2724 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 return -EINVAL;
2726 }
Steve French790fe572007-07-07 19:25:05 +00002727 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 count = le16_to_cpu(cifs_acl->access_entry_count);
2729 size = sizeof(struct cifs_posix_acl);
2730 size += sizeof(struct cifs_posix_ace) * count;
2731/* skip past access ACEs to get to default ACEs */
2732 pACE = &cifs_acl->ace_array[count];
2733 count = le16_to_cpu(cifs_acl->default_entry_count);
2734 size += sizeof(struct cifs_posix_ace) * count;
2735 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002736 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 return -EINVAL;
2738 } else {
2739 /* illegal type */
2740 return -EINVAL;
2741 }
2742
2743 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002744 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002745 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002746 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 return -ERANGE;
2748 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002749 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002750 for (i = 0; i < count ; i++) {
2751 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2752 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 }
2754 }
2755 return size;
2756}
2757
Steve French50c2f752007-07-13 00:33:32 +00002758static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2759 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760{
2761 __u16 rc = 0; /* 0 = ACL converted ok */
2762
Steve Frenchff7feac2005-11-15 16:45:16 -08002763 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2764 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002766 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 /* Probably no need to le convert -1 on any arch but can not hurt */
2768 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002769 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002770 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002771 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 return rc;
2773}
2774
2775/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002776static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2777 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778{
2779 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002780 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2781 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 int count;
2783 int i;
2784
Steve French790fe572007-07-07 19:25:05 +00002785 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 return 0;
2787
2788 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002789 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002790 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002791 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002792 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002793 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002794 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 return 0;
2796 }
2797 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002798 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002799 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002800 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002801 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 else {
Steve French50c2f752007-07-13 00:33:32 +00002803 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 return 0;
2805 }
Steve French50c2f752007-07-13 00:33:32 +00002806 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2808 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002809 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 /* ACE not converted */
2811 break;
2812 }
2813 }
Steve French790fe572007-07-07 19:25:05 +00002814 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2816 rc += sizeof(struct cifs_posix_acl);
2817 /* BB add check to make sure ACL does not overflow SMB */
2818 }
2819 return rc;
2820}
2821
2822int
2823CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002824 const unsigned char *searchName,
2825 char *acl_inf, const int buflen, const int acl_type,
2826 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827{
2828/* SMB_QUERY_POSIX_ACL */
2829 TRANSACTION2_QPI_REQ *pSMB = NULL;
2830 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2831 int rc = 0;
2832 int bytes_returned;
2833 int name_len;
2834 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002835
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2837
2838queryAclRetry:
2839 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2840 (void **) &pSMBr);
2841 if (rc)
2842 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002843
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2845 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002846 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002847 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 name_len++; /* trailing null */
2849 name_len *= 2;
2850 pSMB->FileName[name_len] = 0;
2851 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002852 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 name_len = strnlen(searchName, PATH_MAX);
2854 name_len++; /* trailing null */
2855 strncpy(pSMB->FileName, searchName, name_len);
2856 }
2857
2858 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2859 pSMB->TotalDataCount = 0;
2860 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002861 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 pSMB->MaxDataCount = cpu_to_le16(4000);
2863 pSMB->MaxSetupCount = 0;
2864 pSMB->Reserved = 0;
2865 pSMB->Flags = 0;
2866 pSMB->Timeout = 0;
2867 pSMB->Reserved2 = 0;
2868 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002869 offsetof(struct smb_com_transaction2_qpi_req,
2870 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 pSMB->DataCount = 0;
2872 pSMB->DataOffset = 0;
2873 pSMB->SetupCount = 1;
2874 pSMB->Reserved3 = 0;
2875 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2876 byte_count = params + 1 /* pad */ ;
2877 pSMB->TotalParameterCount = cpu_to_le16(params);
2878 pSMB->ParameterCount = pSMB->TotalParameterCount;
2879 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2880 pSMB->Reserved4 = 0;
2881 pSMB->hdr.smb_buf_length += byte_count;
2882 pSMB->ByteCount = cpu_to_le16(byte_count);
2883
2884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002886 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 if (rc) {
2888 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2889 } else {
2890 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002891
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2893 if (rc || (pSMBr->ByteCount < 2))
2894 /* BB also check enough total bytes returned */
2895 rc = -EIO; /* bad smb */
2896 else {
2897 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2898 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2899 rc = cifs_copy_posix_acl(acl_inf,
2900 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002901 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 }
2903 }
2904 cifs_buf_release(pSMB);
2905 if (rc == -EAGAIN)
2906 goto queryAclRetry;
2907 return rc;
2908}
2909
2910int
2911CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002912 const unsigned char *fileName,
2913 const char *local_acl, const int buflen,
2914 const int acl_type,
2915 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916{
2917 struct smb_com_transaction2_spi_req *pSMB = NULL;
2918 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2919 char *parm_data;
2920 int name_len;
2921 int rc = 0;
2922 int bytes_returned = 0;
2923 __u16 params, byte_count, data_count, param_offset, offset;
2924
2925 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2926setAclRetry:
2927 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002928 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 if (rc)
2930 return rc;
2931 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2932 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002933 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002934 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 name_len++; /* trailing null */
2936 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002937 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 name_len = strnlen(fileName, PATH_MAX);
2939 name_len++; /* trailing null */
2940 strncpy(pSMB->FileName, fileName, name_len);
2941 }
2942 params = 6 + name_len;
2943 pSMB->MaxParameterCount = cpu_to_le16(2);
2944 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2945 pSMB->MaxSetupCount = 0;
2946 pSMB->Reserved = 0;
2947 pSMB->Flags = 0;
2948 pSMB->Timeout = 0;
2949 pSMB->Reserved2 = 0;
2950 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002951 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 offset = param_offset + params;
2953 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2954 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2955
2956 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002957 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
Steve French790fe572007-07-07 19:25:05 +00002959 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 rc = -EOPNOTSUPP;
2961 goto setACLerrorExit;
2962 }
2963 pSMB->DataOffset = cpu_to_le16(offset);
2964 pSMB->SetupCount = 1;
2965 pSMB->Reserved3 = 0;
2966 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2967 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2968 byte_count = 3 /* pad */ + params + data_count;
2969 pSMB->DataCount = cpu_to_le16(data_count);
2970 pSMB->TotalDataCount = pSMB->DataCount;
2971 pSMB->ParameterCount = cpu_to_le16(params);
2972 pSMB->TotalParameterCount = pSMB->ParameterCount;
2973 pSMB->Reserved4 = 0;
2974 pSMB->hdr.smb_buf_length += byte_count;
2975 pSMB->ByteCount = cpu_to_le16(byte_count);
2976 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002977 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 if (rc) {
2979 cFYI(1, ("Set POSIX ACL returned %d", rc));
2980 }
2981
2982setACLerrorExit:
2983 cifs_buf_release(pSMB);
2984 if (rc == -EAGAIN)
2985 goto setAclRetry;
2986 return rc;
2987}
2988
Steve Frenchf654bac2005-04-28 22:41:04 -07002989/* BB fix tabs in this function FIXME BB */
2990int
2991CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002992 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002993{
Steve French50c2f752007-07-13 00:33:32 +00002994 int rc = 0;
2995 struct smb_t2_qfi_req *pSMB = NULL;
2996 struct smb_t2_qfi_rsp *pSMBr = NULL;
2997 int bytes_returned;
2998 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002999
Steve French790fe572007-07-07 19:25:05 +00003000 cFYI(1, ("In GetExtAttr"));
3001 if (tcon == NULL)
3002 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003003
3004GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003005 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3006 (void **) &pSMBr);
3007 if (rc)
3008 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003009
Steve French790fe572007-07-07 19:25:05 +00003010 params = 2 /* level */ +2 /* fid */;
3011 pSMB->t2.TotalDataCount = 0;
3012 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3013 /* BB find exact max data count below from sess structure BB */
3014 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3015 pSMB->t2.MaxSetupCount = 0;
3016 pSMB->t2.Reserved = 0;
3017 pSMB->t2.Flags = 0;
3018 pSMB->t2.Timeout = 0;
3019 pSMB->t2.Reserved2 = 0;
3020 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3021 Fid) - 4);
3022 pSMB->t2.DataCount = 0;
3023 pSMB->t2.DataOffset = 0;
3024 pSMB->t2.SetupCount = 1;
3025 pSMB->t2.Reserved3 = 0;
3026 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3027 byte_count = params + 1 /* pad */ ;
3028 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3029 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3030 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3031 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003032 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003033 pSMB->hdr.smb_buf_length += byte_count;
3034 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003035
Steve French790fe572007-07-07 19:25:05 +00003036 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3037 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3038 if (rc) {
3039 cFYI(1, ("error %d in GetExtAttr", rc));
3040 } else {
3041 /* decode response */
3042 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3043 if (rc || (pSMBr->ByteCount < 2))
3044 /* BB also check enough total bytes returned */
3045 /* If rc should we check for EOPNOSUPP and
3046 disable the srvino flag? or in caller? */
3047 rc = -EIO; /* bad smb */
3048 else {
3049 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3050 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3051 struct file_chattr_info *pfinfo;
3052 /* BB Do we need a cast or hash here ? */
3053 if (count != 16) {
3054 cFYI(1, ("Illegal size ret in GetExtAttr"));
3055 rc = -EIO;
3056 goto GetExtAttrOut;
3057 }
3058 pfinfo = (struct file_chattr_info *)
3059 (data_offset + (char *) &pSMBr->hdr.Protocol);
3060 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003061 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003062 }
3063 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003064GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003065 cifs_buf_release(pSMB);
3066 if (rc == -EAGAIN)
3067 goto GetExtAttrRetry;
3068 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003069}
3070
Steve Frenchf654bac2005-04-28 22:41:04 -07003071#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072
Steve French297647c2007-10-12 04:11:59 +00003073#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003074/* Get Security Descriptor (by handle) from remote server for a file or dir */
3075int
3076CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003077 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003078{
3079 int rc = 0;
3080 int buf_type = 0;
3081 QUERY_SEC_DESC_REQ * pSMB;
3082 struct kvec iov[1];
3083
3084 cFYI(1, ("GetCifsACL"));
3085
Steve French630f3f02007-10-25 21:17:17 +00003086 *pbuflen = 0;
3087 *acl_inf = NULL;
3088
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003089 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003090 8 /* parm len */, tcon, (void **) &pSMB);
3091 if (rc)
3092 return rc;
3093
3094 pSMB->MaxParameterCount = cpu_to_le32(4);
3095 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3096 pSMB->MaxSetupCount = 0;
3097 pSMB->Fid = fid; /* file handle always le */
3098 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3099 CIFS_ACL_DACL);
3100 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3101 pSMB->hdr.smb_buf_length += 11;
3102 iov[0].iov_base = (char *)pSMB;
3103 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3104
Steve Frencha761ac52007-10-18 21:45:27 +00003105 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3106 0 /* not long op */, 0 /* do not log STATUS codes */ );
Steve French0a4b92c2006-01-12 15:44:21 -08003107 cifs_stats_inc(&tcon->num_acl_get);
3108 if (rc) {
3109 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3110 } else { /* decode response */
Steve French0a4b92c2006-01-12 15:44:21 -08003111 __le32 * parm;
Steve French630f3f02007-10-25 21:17:17 +00003112 __u32 parm_len;
3113 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003114 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003115 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003116
3117/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003118 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003119 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003120 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003121 goto qsec_out;
3122 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3123
Steve French630f3f02007-10-25 21:17:17 +00003124 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003125
3126 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3127 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003128 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003129 goto qsec_out;
3130 }
3131
3132/* BB check that data area is minimum length and as big as acl_len */
3133
Steve Frenchaf6f4612007-10-16 18:40:37 +00003134 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003135 if (acl_len != *pbuflen) {
3136 cERROR(1, ("acl length %d does not match %d",
3137 acl_len, *pbuflen));
3138 if (*pbuflen > acl_len)
3139 *pbuflen = acl_len;
3140 }
Steve French0a4b92c2006-01-12 15:44:21 -08003141
Steve French630f3f02007-10-25 21:17:17 +00003142 /* check if buffer is big enough for the acl
3143 header followed by the smallest SID */
3144 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3145 (*pbuflen >= 64 * 1024)) {
3146 cERROR(1, ("bad acl length %d", *pbuflen));
3147 rc = -EINVAL;
3148 *pbuflen = 0;
3149 } else {
3150 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3151 if (*acl_inf == NULL) {
3152 *pbuflen = 0;
3153 rc = -ENOMEM;
3154 }
3155 memcpy(*acl_inf, pdata, *pbuflen);
3156 }
Steve French0a4b92c2006-01-12 15:44:21 -08003157 }
3158qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003159 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003160 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003161 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003162 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003163/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003164 return rc;
3165}
Steve French297647c2007-10-12 04:11:59 +00003166#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003167
Steve French6b8edfe2005-08-23 20:26:03 -07003168/* Legacy Query Path Information call for lookup to old servers such
3169 as Win9x/WinME */
3170int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003171 const unsigned char *searchName,
3172 FILE_ALL_INFO *pFinfo,
3173 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003174{
3175 QUERY_INFORMATION_REQ * pSMB;
3176 QUERY_INFORMATION_RSP * pSMBr;
3177 int rc = 0;
3178 int bytes_returned;
3179 int name_len;
3180
Steve French50c2f752007-07-13 00:33:32 +00003181 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003182QInfRetry:
3183 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003184 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003185 if (rc)
3186 return rc;
3187
3188 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3189 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003190 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3191 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003192 name_len++; /* trailing null */
3193 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003194 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003195 name_len = strnlen(searchName, PATH_MAX);
3196 name_len++; /* trailing null */
3197 strncpy(pSMB->FileName, searchName, name_len);
3198 }
3199 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003200 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003201 pSMB->hdr.smb_buf_length += (__u16) name_len;
3202 pSMB->ByteCount = cpu_to_le16(name_len);
3203
3204 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003205 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003206 if (rc) {
3207 cFYI(1, ("Send error in QueryInfo = %d", rc));
3208 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003209 struct timespec ts;
3210 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3211 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003212 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003213 ts.tv_nsec = 0;
3214 ts.tv_sec = time;
3215 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003216 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003217 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3218 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003219 pFinfo->AllocationSize =
3220 cpu_to_le64(le32_to_cpu(pSMBr->size));
3221 pFinfo->EndOfFile = pFinfo->AllocationSize;
3222 pFinfo->Attributes =
3223 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003224 } else
3225 rc = -EIO; /* bad buffer passed in */
3226
3227 cifs_buf_release(pSMB);
3228
3229 if (rc == -EAGAIN)
3230 goto QInfRetry;
3231
3232 return rc;
3233}
3234
3235
3236
3237
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238int
3239CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3240 const unsigned char *searchName,
3241 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003242 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003243 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244{
3245/* level 263 SMB_QUERY_FILE_ALL_INFO */
3246 TRANSACTION2_QPI_REQ *pSMB = NULL;
3247 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3248 int rc = 0;
3249 int bytes_returned;
3250 int name_len;
3251 __u16 params, byte_count;
3252
3253/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3254QPathInfoRetry:
3255 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3256 (void **) &pSMBr);
3257 if (rc)
3258 return rc;
3259
3260 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3261 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003262 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003263 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 name_len++; /* trailing null */
3265 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003266 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 name_len = strnlen(searchName, PATH_MAX);
3268 name_len++; /* trailing null */
3269 strncpy(pSMB->FileName, searchName, name_len);
3270 }
3271
Steve French50c2f752007-07-13 00:33:32 +00003272 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 pSMB->TotalDataCount = 0;
3274 pSMB->MaxParameterCount = cpu_to_le16(2);
3275 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3276 pSMB->MaxSetupCount = 0;
3277 pSMB->Reserved = 0;
3278 pSMB->Flags = 0;
3279 pSMB->Timeout = 0;
3280 pSMB->Reserved2 = 0;
3281 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003282 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 pSMB->DataCount = 0;
3284 pSMB->DataOffset = 0;
3285 pSMB->SetupCount = 1;
3286 pSMB->Reserved3 = 0;
3287 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3288 byte_count = params + 1 /* pad */ ;
3289 pSMB->TotalParameterCount = cpu_to_le16(params);
3290 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003291 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003292 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3293 else
3294 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 pSMB->Reserved4 = 0;
3296 pSMB->hdr.smb_buf_length += byte_count;
3297 pSMB->ByteCount = cpu_to_le16(byte_count);
3298
3299 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3300 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3301 if (rc) {
3302 cFYI(1, ("Send error in QPathInfo = %d", rc));
3303 } else { /* decode response */
3304 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3305
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003306 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3307 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003308 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003310 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003311 rc = -EIO; /* 24 or 26 expected but we do not read
3312 last field */
3313 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003314 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003316 if (legacy) /* we do not read the last field, EAsize,
3317 fortunately since it varies by subdialect
3318 and on Set vs. Get, is two bytes or 4
3319 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003320 size = sizeof(FILE_INFO_STANDARD);
3321 else
3322 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 memcpy((char *) pFindData,
3324 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003325 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 } else
3327 rc = -ENOMEM;
3328 }
3329 cifs_buf_release(pSMB);
3330 if (rc == -EAGAIN)
3331 goto QPathInfoRetry;
3332
3333 return rc;
3334}
3335
3336int
3337CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3338 const unsigned char *searchName,
3339 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003340 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341{
3342/* SMB_QUERY_FILE_UNIX_BASIC */
3343 TRANSACTION2_QPI_REQ *pSMB = NULL;
3344 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3345 int rc = 0;
3346 int bytes_returned = 0;
3347 int name_len;
3348 __u16 params, byte_count;
3349
3350 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3351UnixQPathInfoRetry:
3352 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3353 (void **) &pSMBr);
3354 if (rc)
3355 return rc;
3356
3357 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3358 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003359 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003360 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 name_len++; /* trailing null */
3362 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003363 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 name_len = strnlen(searchName, PATH_MAX);
3365 name_len++; /* trailing null */
3366 strncpy(pSMB->FileName, searchName, name_len);
3367 }
3368
Steve French50c2f752007-07-13 00:33:32 +00003369 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 pSMB->TotalDataCount = 0;
3371 pSMB->MaxParameterCount = cpu_to_le16(2);
3372 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003373 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 pSMB->MaxSetupCount = 0;
3375 pSMB->Reserved = 0;
3376 pSMB->Flags = 0;
3377 pSMB->Timeout = 0;
3378 pSMB->Reserved2 = 0;
3379 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003380 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 pSMB->DataCount = 0;
3382 pSMB->DataOffset = 0;
3383 pSMB->SetupCount = 1;
3384 pSMB->Reserved3 = 0;
3385 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3386 byte_count = params + 1 /* pad */ ;
3387 pSMB->TotalParameterCount = cpu_to_le16(params);
3388 pSMB->ParameterCount = pSMB->TotalParameterCount;
3389 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3390 pSMB->Reserved4 = 0;
3391 pSMB->hdr.smb_buf_length += byte_count;
3392 pSMB->ByteCount = cpu_to_le16(byte_count);
3393
3394 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3395 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3396 if (rc) {
3397 cFYI(1, ("Send error in QPathInfo = %d", rc));
3398 } else { /* decode response */
3399 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3400
3401 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003402 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3403 "Unix Extensions can be disabled on mount "
3404 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 rc = -EIO; /* bad smb */
3406 } else {
3407 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3408 memcpy((char *) pFindData,
3409 (char *) &pSMBr->hdr.Protocol +
3410 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003411 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 }
3413 }
3414 cifs_buf_release(pSMB);
3415 if (rc == -EAGAIN)
3416 goto UnixQPathInfoRetry;
3417
3418 return rc;
3419}
3420
3421#if 0 /* function unused at present */
3422int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3423 const char *searchName, FILE_ALL_INFO * findData,
3424 const struct nls_table *nls_codepage)
3425{
3426/* level 257 SMB_ */
3427 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3428 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3429 int rc = 0;
3430 int bytes_returned;
3431 int name_len;
3432 __u16 params, byte_count;
3433
3434 cFYI(1, ("In FindUnique"));
3435findUniqueRetry:
3436 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3437 (void **) &pSMBr);
3438 if (rc)
3439 return rc;
3440
3441 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3442 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003443 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3444 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 name_len++; /* trailing null */
3446 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003447 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 name_len = strnlen(searchName, PATH_MAX);
3449 name_len++; /* trailing null */
3450 strncpy(pSMB->FileName, searchName, name_len);
3451 }
3452
3453 params = 12 + name_len /* includes null */ ;
3454 pSMB->TotalDataCount = 0; /* no EAs */
3455 pSMB->MaxParameterCount = cpu_to_le16(2);
3456 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3457 pSMB->MaxSetupCount = 0;
3458 pSMB->Reserved = 0;
3459 pSMB->Flags = 0;
3460 pSMB->Timeout = 0;
3461 pSMB->Reserved2 = 0;
3462 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003463 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 pSMB->DataCount = 0;
3465 pSMB->DataOffset = 0;
3466 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3467 pSMB->Reserved3 = 0;
3468 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3469 byte_count = params + 1 /* pad */ ;
3470 pSMB->TotalParameterCount = cpu_to_le16(params);
3471 pSMB->ParameterCount = pSMB->TotalParameterCount;
3472 pSMB->SearchAttributes =
3473 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3474 ATTR_DIRECTORY);
3475 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3476 pSMB->SearchFlags = cpu_to_le16(1);
3477 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3478 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3479 pSMB->hdr.smb_buf_length += byte_count;
3480 pSMB->ByteCount = cpu_to_le16(byte_count);
3481
3482 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3483 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3484
3485 if (rc) {
3486 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3487 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003488 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 /* BB fill in */
3490 }
3491
3492 cifs_buf_release(pSMB);
3493 if (rc == -EAGAIN)
3494 goto findUniqueRetry;
3495
3496 return rc;
3497}
3498#endif /* end unused (temporarily) function */
3499
3500/* xid, tcon, searchName and codepage are input parms, rest are returned */
3501int
3502CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003503 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003505 __u16 *pnetfid,
3506 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507{
3508/* level 257 SMB_ */
3509 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3510 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3511 T2_FFIRST_RSP_PARMS * parms;
3512 int rc = 0;
3513 int bytes_returned = 0;
3514 int name_len;
3515 __u16 params, byte_count;
3516
Steve French50c2f752007-07-13 00:33:32 +00003517 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
3519findFirstRetry:
3520 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3521 (void **) &pSMBr);
3522 if (rc)
3523 return rc;
3524
3525 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3526 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003527 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003528 PATH_MAX, nls_codepage, remap);
3529 /* We can not add the asterik earlier in case
3530 it got remapped to 0xF03A as if it were part of the
3531 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003533 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003534 pSMB->FileName[name_len+1] = 0;
3535 pSMB->FileName[name_len+2] = '*';
3536 pSMB->FileName[name_len+3] = 0;
3537 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3539 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003540 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 } else { /* BB add check for overrun of SMB buf BB */
3542 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003544 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 free buffer exit; BB */
3546 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003547 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003548 pSMB->FileName[name_len+1] = '*';
3549 pSMB->FileName[name_len+2] = 0;
3550 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 }
3552
3553 params = 12 + name_len /* includes null */ ;
3554 pSMB->TotalDataCount = 0; /* no EAs */
3555 pSMB->MaxParameterCount = cpu_to_le16(10);
3556 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3557 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3558 pSMB->MaxSetupCount = 0;
3559 pSMB->Reserved = 0;
3560 pSMB->Flags = 0;
3561 pSMB->Timeout = 0;
3562 pSMB->Reserved2 = 0;
3563 byte_count = params + 1 /* pad */ ;
3564 pSMB->TotalParameterCount = cpu_to_le16(params);
3565 pSMB->ParameterCount = pSMB->TotalParameterCount;
3566 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003567 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3568 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 pSMB->DataCount = 0;
3570 pSMB->DataOffset = 0;
3571 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3572 pSMB->Reserved3 = 0;
3573 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3574 pSMB->SearchAttributes =
3575 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3576 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003577 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3578 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 CIFS_SEARCH_RETURN_RESUME);
3580 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3581
3582 /* BB what should we set StorageType to? Does it matter? BB */
3583 pSMB->SearchStorageType = 0;
3584 pSMB->hdr.smb_buf_length += byte_count;
3585 pSMB->ByteCount = cpu_to_le16(byte_count);
3586
3587 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3588 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003589 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590
Steve French88274812006-03-09 22:21:45 +00003591 if (rc) {/* BB add logic to retry regular search if Unix search
3592 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 /* BB Add code to handle unsupported level rc */
3594 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003595
Steve French88274812006-03-09 22:21:45 +00003596 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597
3598 /* BB eventually could optimize out free and realloc of buf */
3599 /* for this case */
3600 if (rc == -EAGAIN)
3601 goto findFirstRetry;
3602 } else { /* decode response */
3603 /* BB remember to free buffer if error BB */
3604 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003605 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3607 psrch_inf->unicode = TRUE;
3608 else
3609 psrch_inf->unicode = FALSE;
3610
3611 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003612 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003613 psrch_inf->srch_entries_start =
3614 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3617 le16_to_cpu(pSMBr->t2.ParameterOffset));
3618
Steve French790fe572007-07-07 19:25:05 +00003619 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 psrch_inf->endOfSearch = TRUE;
3621 else
3622 psrch_inf->endOfSearch = FALSE;
3623
Steve French50c2f752007-07-13 00:33:32 +00003624 psrch_inf->entries_in_buffer =
3625 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003626 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 *pnetfid = parms->SearchHandle;
3629 } else {
3630 cifs_buf_release(pSMB);
3631 }
3632 }
3633
3634 return rc;
3635}
3636
3637int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003638 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639{
3640 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3641 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3642 T2_FNEXT_RSP_PARMS * parms;
3643 char *response_data;
3644 int rc = 0;
3645 int bytes_returned, name_len;
3646 __u16 params, byte_count;
3647
3648 cFYI(1, ("In FindNext"));
3649
Steve French790fe572007-07-07 19:25:05 +00003650 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 return -ENOENT;
3652
3653 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3654 (void **) &pSMBr);
3655 if (rc)
3656 return rc;
3657
Steve French50c2f752007-07-13 00:33:32 +00003658 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 byte_count = 0;
3660 pSMB->TotalDataCount = 0; /* no EAs */
3661 pSMB->MaxParameterCount = cpu_to_le16(8);
3662 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003663 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3664 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 pSMB->MaxSetupCount = 0;
3666 pSMB->Reserved = 0;
3667 pSMB->Flags = 0;
3668 pSMB->Timeout = 0;
3669 pSMB->Reserved2 = 0;
3670 pSMB->ParameterOffset = cpu_to_le16(
3671 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3672 pSMB->DataCount = 0;
3673 pSMB->DataOffset = 0;
3674 pSMB->SetupCount = 1;
3675 pSMB->Reserved3 = 0;
3676 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3677 pSMB->SearchHandle = searchHandle; /* always kept as le */
3678 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003679 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3681 pSMB->ResumeKey = psrch_inf->resume_key;
3682 pSMB->SearchFlags =
3683 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3684
3685 name_len = psrch_inf->resume_name_len;
3686 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003687 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3689 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003690 /* 14 byte parm len above enough for 2 byte null terminator */
3691 pSMB->ResumeFileName[name_len] = 0;
3692 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 } else {
3694 rc = -EINVAL;
3695 goto FNext2_err_exit;
3696 }
3697 byte_count = params + 1 /* pad */ ;
3698 pSMB->TotalParameterCount = cpu_to_le16(params);
3699 pSMB->ParameterCount = pSMB->TotalParameterCount;
3700 pSMB->hdr.smb_buf_length += byte_count;
3701 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003702
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3704 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003705 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 if (rc) {
3707 if (rc == -EBADF) {
3708 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003709 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 } else
3711 cFYI(1, ("FindNext returned = %d", rc));
3712 } else { /* decode response */
3713 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003714
Steve French790fe572007-07-07 19:25:05 +00003715 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 /* BB fixme add lock for file (srch_info) struct here */
3717 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3718 psrch_inf->unicode = TRUE;
3719 else
3720 psrch_inf->unicode = FALSE;
3721 response_data = (char *) &pSMBr->hdr.Protocol +
3722 le16_to_cpu(pSMBr->t2.ParameterOffset);
3723 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3724 response_data = (char *)&pSMBr->hdr.Protocol +
3725 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003726 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003727 cifs_small_buf_release(
3728 psrch_inf->ntwrk_buf_start);
3729 else
3730 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 psrch_inf->srch_entries_start = response_data;
3732 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003733 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003734 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 psrch_inf->endOfSearch = TRUE;
3736 else
3737 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003738 psrch_inf->entries_in_buffer =
3739 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 psrch_inf->index_of_last_entry +=
3741 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003742/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3743 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744
3745 /* BB fixme add unlock here */
3746 }
3747
3748 }
3749
3750 /* BB On error, should we leave previous search buf (and count and
3751 last entry fields) intact or free the previous one? */
3752
3753 /* Note: On -EAGAIN error only caller can retry on handle based calls
3754 since file handle passed in no longer valid */
3755FNext2_err_exit:
3756 if (rc != 0)
3757 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 return rc;
3759}
3760
3761int
Steve French50c2f752007-07-13 00:33:32 +00003762CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3763 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764{
3765 int rc = 0;
3766 FINDCLOSE_REQ *pSMB = NULL;
3767 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3768 int bytes_returned;
3769
3770 cFYI(1, ("In CIFSSMBFindClose"));
3771 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3772
3773 /* no sense returning error if session restarted
3774 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003775 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 return 0;
3777 if (rc)
3778 return rc;
3779
3780 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3781 pSMB->FileID = searchHandle;
3782 pSMB->ByteCount = 0;
3783 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3784 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3785 if (rc) {
3786 cERROR(1, ("Send error in FindClose = %d", rc));
3787 }
Steve Frencha4544342005-08-24 13:59:35 -07003788 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 cifs_small_buf_release(pSMB);
3790
3791 /* Since session is dead, search handle closed on server already */
3792 if (rc == -EAGAIN)
3793 rc = 0;
3794
3795 return rc;
3796}
3797
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798int
3799CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003800 const unsigned char *searchName,
3801 __u64 * inode_number,
3802 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803{
3804 int rc = 0;
3805 TRANSACTION2_QPI_REQ *pSMB = NULL;
3806 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3807 int name_len, bytes_returned;
3808 __u16 params, byte_count;
3809
Steve French50c2f752007-07-13 00:33:32 +00003810 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003811 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003812 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813
3814GetInodeNumberRetry:
3815 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003816 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 if (rc)
3818 return rc;
3819
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3821 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003822 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003823 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 name_len++; /* trailing null */
3825 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003826 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 name_len = strnlen(searchName, PATH_MAX);
3828 name_len++; /* trailing null */
3829 strncpy(pSMB->FileName, searchName, name_len);
3830 }
3831
3832 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3833 pSMB->TotalDataCount = 0;
3834 pSMB->MaxParameterCount = cpu_to_le16(2);
3835 /* BB find exact max data count below from sess structure BB */
3836 pSMB->MaxDataCount = cpu_to_le16(4000);
3837 pSMB->MaxSetupCount = 0;
3838 pSMB->Reserved = 0;
3839 pSMB->Flags = 0;
3840 pSMB->Timeout = 0;
3841 pSMB->Reserved2 = 0;
3842 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003843 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 pSMB->DataCount = 0;
3845 pSMB->DataOffset = 0;
3846 pSMB->SetupCount = 1;
3847 pSMB->Reserved3 = 0;
3848 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3849 byte_count = params + 1 /* pad */ ;
3850 pSMB->TotalParameterCount = cpu_to_le16(params);
3851 pSMB->ParameterCount = pSMB->TotalParameterCount;
3852 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3853 pSMB->Reserved4 = 0;
3854 pSMB->hdr.smb_buf_length += byte_count;
3855 pSMB->ByteCount = cpu_to_le16(byte_count);
3856
3857 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3858 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3859 if (rc) {
3860 cFYI(1, ("error %d in QueryInternalInfo", rc));
3861 } else {
3862 /* decode response */
3863 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3864 if (rc || (pSMBr->ByteCount < 2))
3865 /* BB also check enough total bytes returned */
3866 /* If rc should we check for EOPNOSUPP and
3867 disable the srvino flag? or in caller? */
3868 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003869 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3871 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003872 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003874 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3876 rc = -EIO;
3877 goto GetInodeNumOut;
3878 }
3879 pfinfo = (struct file_internal_info *)
3880 (data_offset + (char *) &pSMBr->hdr.Protocol);
3881 *inode_number = pfinfo->UniqueId;
3882 }
3883 }
3884GetInodeNumOut:
3885 cifs_buf_release(pSMB);
3886 if (rc == -EAGAIN)
3887 goto GetInodeNumberRetry;
3888 return rc;
3889}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890
3891int
3892CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3893 const unsigned char *searchName,
3894 unsigned char **targetUNCs,
3895 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003896 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897{
3898/* TRANS2_GET_DFS_REFERRAL */
3899 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3900 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003901 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 int rc = 0;
3903 int bytes_returned;
3904 int name_len;
3905 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003906 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 __u16 params, byte_count;
3908 *number_of_UNC_in_array = 0;
3909 *targetUNCs = NULL;
3910
3911 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3912 if (ses == NULL)
3913 return -ENODEV;
3914getDFSRetry:
3915 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3916 (void **) &pSMBr);
3917 if (rc)
3918 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003919
3920 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003921 but should never be null here anyway */
3922 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 pSMB->hdr.Tid = ses->ipc_tid;
3924 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003925 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003927 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929
3930 if (ses->capabilities & CAP_UNICODE) {
3931 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3932 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003933 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003934 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 name_len++; /* trailing null */
3936 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003937 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 name_len = strnlen(searchName, PATH_MAX);
3939 name_len++; /* trailing null */
3940 strncpy(pSMB->RequestFileName, searchName, name_len);
3941 }
3942
Steve French790fe572007-07-07 19:25:05 +00003943 if (ses->server) {
3944 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003945 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3946 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3947 }
3948
Steve French50c2f752007-07-13 00:33:32 +00003949 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003950
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 params = 2 /* level */ + name_len /*includes null */ ;
3952 pSMB->TotalDataCount = 0;
3953 pSMB->DataCount = 0;
3954 pSMB->DataOffset = 0;
3955 pSMB->MaxParameterCount = 0;
3956 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3957 pSMB->MaxSetupCount = 0;
3958 pSMB->Reserved = 0;
3959 pSMB->Flags = 0;
3960 pSMB->Timeout = 0;
3961 pSMB->Reserved2 = 0;
3962 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003963 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 pSMB->SetupCount = 1;
3965 pSMB->Reserved3 = 0;
3966 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3967 byte_count = params + 3 /* pad */ ;
3968 pSMB->ParameterCount = cpu_to_le16(params);
3969 pSMB->TotalParameterCount = pSMB->ParameterCount;
3970 pSMB->MaxReferralLevel = cpu_to_le16(3);
3971 pSMB->hdr.smb_buf_length += byte_count;
3972 pSMB->ByteCount = cpu_to_le16(byte_count);
3973
3974 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3976 if (rc) {
3977 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3978 } else { /* decode response */
3979/* BB Add logic to parse referrals here */
3980 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3981
Steve French50c2f752007-07-13 00:33:32 +00003982 /* BB Also check if enough total bytes returned? */
3983 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 rc = -EIO; /* bad smb */
3985 else {
Steve French50c2f752007-07-13 00:33:32 +00003986 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3988
3989 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003990 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003992 referrals =
3993 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 (8 /* sizeof start of data block */ +
3995 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003996 (char *) &pSMBr->hdr.Protocol);
Steve Frenchc18c8422007-07-18 23:21:09 +00003997 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
Steve French63135e02007-07-17 17:34:02 +00003998 "for referral one refer size: 0x%x srv "
3999 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00004000 le16_to_cpu(pSMBr->NumberOfReferrals),
4001 le16_to_cpu(pSMBr->DFSFlags),
4002 le16_to_cpu(referrals->ReferralSize),
4003 le16_to_cpu(referrals->ServerType),
4004 le16_to_cpu(referrals->ReferralFlags),
4005 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 /* BB This field is actually two bytes in from start of
4007 data block so we could do safety check that DataBlock
4008 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00004009 *number_of_UNC_in_array =
4010 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011
4012 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00004013 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 *number_of_UNC_in_array = 1;
4015
4016 /* get the length of the strings describing refs */
4017 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00004018 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00004020 __u16 offset =
4021 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00004023 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 not try to copy any more */
4025 *number_of_UNC_in_array = i;
4026 break;
Steve French50c2f752007-07-13 00:33:32 +00004027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 temp = ((char *)referrals) + offset;
4029
4030 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00004031 name_len += UniStrnlen((wchar_t *)temp,
4032 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 } else {
Steve French50c2f752007-07-13 00:33:32 +00004034 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 }
4036 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004037 /* BB add check that referral pointer does
4038 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 }
4040 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004041 *targetUNCs =
4042 kmalloc(name_len+1+(*number_of_UNC_in_array),
4043 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004044 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 rc = -ENOMEM;
4046 goto GetDFSRefExit;
4047 }
4048 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004049 referrals = (struct dfs_referral_level_3 *)
4050 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 (char *) &pSMBr->hdr.Protocol);
4052
Steve French50c2f752007-07-13 00:33:32 +00004053 for (i = 0; i < *number_of_UNC_in_array; i++) {
4054 temp = ((char *)referrals) +
4055 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4057 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004058 (__le16 *) temp,
4059 name_len,
4060 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 } else {
Steve French50c2f752007-07-13 00:33:32 +00004062 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 }
4064 /* BB update target_uncs pointers */
4065 referrals++;
4066 }
4067 temp = *targetUNCs;
4068 temp[name_len] = 0;
4069 }
4070
4071 }
4072GetDFSRefExit:
4073 if (pSMB)
4074 cifs_buf_release(pSMB);
4075
4076 if (rc == -EAGAIN)
4077 goto getDFSRetry;
4078
4079 return rc;
4080}
4081
Steve French20962432005-09-21 22:05:57 -07004082/* Query File System Info such as free space to old servers such as Win 9x */
4083int
4084SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4085{
4086/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4087 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4088 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4089 FILE_SYSTEM_ALLOC_INFO *response_data;
4090 int rc = 0;
4091 int bytes_returned = 0;
4092 __u16 params, byte_count;
4093
4094 cFYI(1, ("OldQFSInfo"));
4095oldQFSInfoRetry:
4096 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4097 (void **) &pSMBr);
4098 if (rc)
4099 return rc;
Steve French20962432005-09-21 22:05:57 -07004100
4101 params = 2; /* level */
4102 pSMB->TotalDataCount = 0;
4103 pSMB->MaxParameterCount = cpu_to_le16(2);
4104 pSMB->MaxDataCount = cpu_to_le16(1000);
4105 pSMB->MaxSetupCount = 0;
4106 pSMB->Reserved = 0;
4107 pSMB->Flags = 0;
4108 pSMB->Timeout = 0;
4109 pSMB->Reserved2 = 0;
4110 byte_count = params + 1 /* pad */ ;
4111 pSMB->TotalParameterCount = cpu_to_le16(params);
4112 pSMB->ParameterCount = pSMB->TotalParameterCount;
4113 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4114 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4115 pSMB->DataCount = 0;
4116 pSMB->DataOffset = 0;
4117 pSMB->SetupCount = 1;
4118 pSMB->Reserved3 = 0;
4119 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4120 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4121 pSMB->hdr.smb_buf_length += byte_count;
4122 pSMB->ByteCount = cpu_to_le16(byte_count);
4123
4124 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4125 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4126 if (rc) {
4127 cFYI(1, ("Send error in QFSInfo = %d", rc));
4128 } else { /* decode response */
4129 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4130
4131 if (rc || (pSMBr->ByteCount < 18))
4132 rc = -EIO; /* bad smb */
4133 else {
4134 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004135 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004136 pSMBr->ByteCount, data_offset));
4137
Steve French50c2f752007-07-13 00:33:32 +00004138 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004139 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4140 FSData->f_bsize =
4141 le16_to_cpu(response_data->BytesPerSector) *
4142 le32_to_cpu(response_data->
4143 SectorsPerAllocationUnit);
4144 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004145 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004146 FSData->f_bfree = FSData->f_bavail =
4147 le32_to_cpu(response_data->FreeAllocationUnits);
4148 cFYI(1,
4149 ("Blocks: %lld Free: %lld Block size %ld",
4150 (unsigned long long)FSData->f_blocks,
4151 (unsigned long long)FSData->f_bfree,
4152 FSData->f_bsize));
4153 }
4154 }
4155 cifs_buf_release(pSMB);
4156
4157 if (rc == -EAGAIN)
4158 goto oldQFSInfoRetry;
4159
4160 return rc;
4161}
4162
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163int
Steve French737b7582005-04-28 22:41:06 -07004164CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165{
4166/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4167 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4168 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4169 FILE_SYSTEM_INFO *response_data;
4170 int rc = 0;
4171 int bytes_returned = 0;
4172 __u16 params, byte_count;
4173
4174 cFYI(1, ("In QFSInfo"));
4175QFSInfoRetry:
4176 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4177 (void **) &pSMBr);
4178 if (rc)
4179 return rc;
4180
4181 params = 2; /* level */
4182 pSMB->TotalDataCount = 0;
4183 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004184 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 pSMB->MaxSetupCount = 0;
4186 pSMB->Reserved = 0;
4187 pSMB->Flags = 0;
4188 pSMB->Timeout = 0;
4189 pSMB->Reserved2 = 0;
4190 byte_count = params + 1 /* pad */ ;
4191 pSMB->TotalParameterCount = cpu_to_le16(params);
4192 pSMB->ParameterCount = pSMB->TotalParameterCount;
4193 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004194 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 pSMB->DataCount = 0;
4196 pSMB->DataOffset = 0;
4197 pSMB->SetupCount = 1;
4198 pSMB->Reserved3 = 0;
4199 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4200 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4201 pSMB->hdr.smb_buf_length += byte_count;
4202 pSMB->ByteCount = cpu_to_le16(byte_count);
4203
4204 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4205 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4206 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004207 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004209 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210
Steve French20962432005-09-21 22:05:57 -07004211 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 rc = -EIO; /* bad smb */
4213 else {
4214 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215
4216 response_data =
4217 (FILE_SYSTEM_INFO
4218 *) (((char *) &pSMBr->hdr.Protocol) +
4219 data_offset);
4220 FSData->f_bsize =
4221 le32_to_cpu(response_data->BytesPerSector) *
4222 le32_to_cpu(response_data->
4223 SectorsPerAllocationUnit);
4224 FSData->f_blocks =
4225 le64_to_cpu(response_data->TotalAllocationUnits);
4226 FSData->f_bfree = FSData->f_bavail =
4227 le64_to_cpu(response_data->FreeAllocationUnits);
4228 cFYI(1,
4229 ("Blocks: %lld Free: %lld Block size %ld",
4230 (unsigned long long)FSData->f_blocks,
4231 (unsigned long long)FSData->f_bfree,
4232 FSData->f_bsize));
4233 }
4234 }
4235 cifs_buf_release(pSMB);
4236
4237 if (rc == -EAGAIN)
4238 goto QFSInfoRetry;
4239
4240 return rc;
4241}
4242
4243int
Steve French737b7582005-04-28 22:41:06 -07004244CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245{
4246/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4247 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4248 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4249 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4250 int rc = 0;
4251 int bytes_returned = 0;
4252 __u16 params, byte_count;
4253
4254 cFYI(1, ("In QFSAttributeInfo"));
4255QFSAttributeRetry:
4256 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4257 (void **) &pSMBr);
4258 if (rc)
4259 return rc;
4260
4261 params = 2; /* level */
4262 pSMB->TotalDataCount = 0;
4263 pSMB->MaxParameterCount = cpu_to_le16(2);
4264 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4265 pSMB->MaxSetupCount = 0;
4266 pSMB->Reserved = 0;
4267 pSMB->Flags = 0;
4268 pSMB->Timeout = 0;
4269 pSMB->Reserved2 = 0;
4270 byte_count = params + 1 /* pad */ ;
4271 pSMB->TotalParameterCount = cpu_to_le16(params);
4272 pSMB->ParameterCount = pSMB->TotalParameterCount;
4273 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004274 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 pSMB->DataCount = 0;
4276 pSMB->DataOffset = 0;
4277 pSMB->SetupCount = 1;
4278 pSMB->Reserved3 = 0;
4279 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4280 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4281 pSMB->hdr.smb_buf_length += byte_count;
4282 pSMB->ByteCount = cpu_to_le16(byte_count);
4283
4284 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4285 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4286 if (rc) {
4287 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4288 } else { /* decode response */
4289 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4290
Steve French50c2f752007-07-13 00:33:32 +00004291 if (rc || (pSMBr->ByteCount < 13)) {
4292 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 rc = -EIO; /* bad smb */
4294 } else {
4295 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4296 response_data =
4297 (FILE_SYSTEM_ATTRIBUTE_INFO
4298 *) (((char *) &pSMBr->hdr.Protocol) +
4299 data_offset);
4300 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004301 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 }
4303 }
4304 cifs_buf_release(pSMB);
4305
4306 if (rc == -EAGAIN)
4307 goto QFSAttributeRetry;
4308
4309 return rc;
4310}
4311
4312int
Steve French737b7582005-04-28 22:41:06 -07004313CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314{
4315/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4316 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4317 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4318 FILE_SYSTEM_DEVICE_INFO *response_data;
4319 int rc = 0;
4320 int bytes_returned = 0;
4321 __u16 params, byte_count;
4322
4323 cFYI(1, ("In QFSDeviceInfo"));
4324QFSDeviceRetry:
4325 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4326 (void **) &pSMBr);
4327 if (rc)
4328 return rc;
4329
4330 params = 2; /* level */
4331 pSMB->TotalDataCount = 0;
4332 pSMB->MaxParameterCount = cpu_to_le16(2);
4333 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4334 pSMB->MaxSetupCount = 0;
4335 pSMB->Reserved = 0;
4336 pSMB->Flags = 0;
4337 pSMB->Timeout = 0;
4338 pSMB->Reserved2 = 0;
4339 byte_count = params + 1 /* pad */ ;
4340 pSMB->TotalParameterCount = cpu_to_le16(params);
4341 pSMB->ParameterCount = pSMB->TotalParameterCount;
4342 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004343 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344
4345 pSMB->DataCount = 0;
4346 pSMB->DataOffset = 0;
4347 pSMB->SetupCount = 1;
4348 pSMB->Reserved3 = 0;
4349 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4350 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4351 pSMB->hdr.smb_buf_length += byte_count;
4352 pSMB->ByteCount = cpu_to_le16(byte_count);
4353
4354 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4355 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4356 if (rc) {
4357 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4358 } else { /* decode response */
4359 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4360
Steve French630f3f02007-10-25 21:17:17 +00004361 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 rc = -EIO; /* bad smb */
4363 else {
4364 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4365 response_data =
Steve French737b7582005-04-28 22:41:06 -07004366 (FILE_SYSTEM_DEVICE_INFO *)
4367 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 data_offset);
4369 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004370 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 }
4372 }
4373 cifs_buf_release(pSMB);
4374
4375 if (rc == -EAGAIN)
4376 goto QFSDeviceRetry;
4377
4378 return rc;
4379}
4380
4381int
Steve French737b7582005-04-28 22:41:06 -07004382CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383{
4384/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4385 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4386 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4387 FILE_SYSTEM_UNIX_INFO *response_data;
4388 int rc = 0;
4389 int bytes_returned = 0;
4390 __u16 params, byte_count;
4391
4392 cFYI(1, ("In QFSUnixInfo"));
4393QFSUnixRetry:
4394 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4395 (void **) &pSMBr);
4396 if (rc)
4397 return rc;
4398
4399 params = 2; /* level */
4400 pSMB->TotalDataCount = 0;
4401 pSMB->DataCount = 0;
4402 pSMB->DataOffset = 0;
4403 pSMB->MaxParameterCount = cpu_to_le16(2);
4404 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4405 pSMB->MaxSetupCount = 0;
4406 pSMB->Reserved = 0;
4407 pSMB->Flags = 0;
4408 pSMB->Timeout = 0;
4409 pSMB->Reserved2 = 0;
4410 byte_count = params + 1 /* pad */ ;
4411 pSMB->ParameterCount = cpu_to_le16(params);
4412 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004413 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4414 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 pSMB->SetupCount = 1;
4416 pSMB->Reserved3 = 0;
4417 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4418 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4419 pSMB->hdr.smb_buf_length += byte_count;
4420 pSMB->ByteCount = cpu_to_le16(byte_count);
4421
4422 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4423 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4424 if (rc) {
4425 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4426 } else { /* decode response */
4427 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4428
4429 if (rc || (pSMBr->ByteCount < 13)) {
4430 rc = -EIO; /* bad smb */
4431 } else {
4432 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4433 response_data =
4434 (FILE_SYSTEM_UNIX_INFO
4435 *) (((char *) &pSMBr->hdr.Protocol) +
4436 data_offset);
4437 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004438 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 }
4440 }
4441 cifs_buf_release(pSMB);
4442
4443 if (rc == -EAGAIN)
4444 goto QFSUnixRetry;
4445
4446
4447 return rc;
4448}
4449
Jeremy Allisonac670552005-06-22 17:26:35 -07004450int
Steve French45abc6e2005-06-23 13:42:03 -05004451CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004452{
4453/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4454 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4455 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4456 int rc = 0;
4457 int bytes_returned = 0;
4458 __u16 params, param_offset, offset, byte_count;
4459
4460 cFYI(1, ("In SETFSUnixInfo"));
4461SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004462 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004463 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4464 (void **) &pSMBr);
4465 if (rc)
4466 return rc;
4467
4468 params = 4; /* 2 bytes zero followed by info level. */
4469 pSMB->MaxSetupCount = 0;
4470 pSMB->Reserved = 0;
4471 pSMB->Flags = 0;
4472 pSMB->Timeout = 0;
4473 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004474 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4475 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004476 offset = param_offset + params;
4477
4478 pSMB->MaxParameterCount = cpu_to_le16(4);
4479 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4480 pSMB->SetupCount = 1;
4481 pSMB->Reserved3 = 0;
4482 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4483 byte_count = 1 /* pad */ + params + 12;
4484
4485 pSMB->DataCount = cpu_to_le16(12);
4486 pSMB->ParameterCount = cpu_to_le16(params);
4487 pSMB->TotalDataCount = pSMB->DataCount;
4488 pSMB->TotalParameterCount = pSMB->ParameterCount;
4489 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4490 pSMB->DataOffset = cpu_to_le16(offset);
4491
4492 /* Params. */
4493 pSMB->FileNum = 0;
4494 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4495
4496 /* Data. */
4497 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4498 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4499 pSMB->ClientUnixCap = cpu_to_le64(cap);
4500
4501 pSMB->hdr.smb_buf_length += byte_count;
4502 pSMB->ByteCount = cpu_to_le16(byte_count);
4503
4504 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4505 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4506 if (rc) {
4507 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4508 } else { /* decode response */
4509 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4510 if (rc) {
4511 rc = -EIO; /* bad smb */
4512 }
4513 }
4514 cifs_buf_release(pSMB);
4515
4516 if (rc == -EAGAIN)
4517 goto SETFSUnixRetry;
4518
4519 return rc;
4520}
4521
4522
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523
4524int
4525CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004526 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527{
4528/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4529 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4530 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4531 FILE_SYSTEM_POSIX_INFO *response_data;
4532 int rc = 0;
4533 int bytes_returned = 0;
4534 __u16 params, byte_count;
4535
4536 cFYI(1, ("In QFSPosixInfo"));
4537QFSPosixRetry:
4538 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4539 (void **) &pSMBr);
4540 if (rc)
4541 return rc;
4542
4543 params = 2; /* level */
4544 pSMB->TotalDataCount = 0;
4545 pSMB->DataCount = 0;
4546 pSMB->DataOffset = 0;
4547 pSMB->MaxParameterCount = cpu_to_le16(2);
4548 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4549 pSMB->MaxSetupCount = 0;
4550 pSMB->Reserved = 0;
4551 pSMB->Flags = 0;
4552 pSMB->Timeout = 0;
4553 pSMB->Reserved2 = 0;
4554 byte_count = params + 1 /* pad */ ;
4555 pSMB->ParameterCount = cpu_to_le16(params);
4556 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004557 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4558 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 pSMB->SetupCount = 1;
4560 pSMB->Reserved3 = 0;
4561 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4562 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4563 pSMB->hdr.smb_buf_length += byte_count;
4564 pSMB->ByteCount = cpu_to_le16(byte_count);
4565
4566 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4567 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4568 if (rc) {
4569 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4570 } else { /* decode response */
4571 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4572
4573 if (rc || (pSMBr->ByteCount < 13)) {
4574 rc = -EIO; /* bad smb */
4575 } else {
4576 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4577 response_data =
4578 (FILE_SYSTEM_POSIX_INFO
4579 *) (((char *) &pSMBr->hdr.Protocol) +
4580 data_offset);
4581 FSData->f_bsize =
4582 le32_to_cpu(response_data->BlockSize);
4583 FSData->f_blocks =
4584 le64_to_cpu(response_data->TotalBlocks);
4585 FSData->f_bfree =
4586 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004587 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 FSData->f_bavail = FSData->f_bfree;
4589 } else {
4590 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004591 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 }
Steve French790fe572007-07-07 19:25:05 +00004593 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004595 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004596 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004598 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 }
4600 }
4601 cifs_buf_release(pSMB);
4602
4603 if (rc == -EAGAIN)
4604 goto QFSPosixRetry;
4605
4606 return rc;
4607}
4608
4609
Steve French50c2f752007-07-13 00:33:32 +00004610/* We can not use write of zero bytes trick to
4611 set file size due to need for large file support. Also note that
4612 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 routine which is only needed to work around a sharing violation bug
4614 in Samba which this routine can run into */
4615
4616int
4617CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004618 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004619 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620{
4621 struct smb_com_transaction2_spi_req *pSMB = NULL;
4622 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4623 struct file_end_of_file_info *parm_data;
4624 int name_len;
4625 int rc = 0;
4626 int bytes_returned = 0;
4627 __u16 params, byte_count, data_count, param_offset, offset;
4628
4629 cFYI(1, ("In SetEOF"));
4630SetEOFRetry:
4631 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4632 (void **) &pSMBr);
4633 if (rc)
4634 return rc;
4635
4636 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4637 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004638 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004639 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 name_len++; /* trailing null */
4641 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004642 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 name_len = strnlen(fileName, PATH_MAX);
4644 name_len++; /* trailing null */
4645 strncpy(pSMB->FileName, fileName, name_len);
4646 }
4647 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004648 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004650 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 pSMB->MaxSetupCount = 0;
4652 pSMB->Reserved = 0;
4653 pSMB->Flags = 0;
4654 pSMB->Timeout = 0;
4655 pSMB->Reserved2 = 0;
4656 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004657 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004659 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004660 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4661 pSMB->InformationLevel =
4662 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4663 else
4664 pSMB->InformationLevel =
4665 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4666 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4668 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004669 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 else
4671 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004672 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 }
4674
4675 parm_data =
4676 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4677 offset);
4678 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4679 pSMB->DataOffset = cpu_to_le16(offset);
4680 pSMB->SetupCount = 1;
4681 pSMB->Reserved3 = 0;
4682 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4683 byte_count = 3 /* pad */ + params + data_count;
4684 pSMB->DataCount = cpu_to_le16(data_count);
4685 pSMB->TotalDataCount = pSMB->DataCount;
4686 pSMB->ParameterCount = cpu_to_le16(params);
4687 pSMB->TotalParameterCount = pSMB->ParameterCount;
4688 pSMB->Reserved4 = 0;
4689 pSMB->hdr.smb_buf_length += byte_count;
4690 parm_data->FileSize = cpu_to_le64(size);
4691 pSMB->ByteCount = cpu_to_le16(byte_count);
4692 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4693 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4694 if (rc) {
4695 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4696 }
4697
4698 cifs_buf_release(pSMB);
4699
4700 if (rc == -EAGAIN)
4701 goto SetEOFRetry;
4702
4703 return rc;
4704}
4705
4706int
Steve French50c2f752007-07-13 00:33:32 +00004707CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4708 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709{
4710 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4711 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4712 char *data_offset;
4713 struct file_end_of_file_info *parm_data;
4714 int rc = 0;
4715 int bytes_returned = 0;
4716 __u16 params, param_offset, offset, byte_count, count;
4717
4718 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4719 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004720 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4721
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 if (rc)
4723 return rc;
4724
Steve Frenchcd634992005-04-28 22:41:10 -07004725 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4726
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4728 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004729
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 params = 6;
4731 pSMB->MaxSetupCount = 0;
4732 pSMB->Reserved = 0;
4733 pSMB->Flags = 0;
4734 pSMB->Timeout = 0;
4735 pSMB->Reserved2 = 0;
4736 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4737 offset = param_offset + params;
4738
Steve French50c2f752007-07-13 00:33:32 +00004739 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740
4741 count = sizeof(struct file_end_of_file_info);
4742 pSMB->MaxParameterCount = cpu_to_le16(2);
4743 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4744 pSMB->SetupCount = 1;
4745 pSMB->Reserved3 = 0;
4746 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4747 byte_count = 3 /* pad */ + params + count;
4748 pSMB->DataCount = cpu_to_le16(count);
4749 pSMB->ParameterCount = cpu_to_le16(params);
4750 pSMB->TotalDataCount = pSMB->DataCount;
4751 pSMB->TotalParameterCount = pSMB->ParameterCount;
4752 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4753 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004754 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4755 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 pSMB->DataOffset = cpu_to_le16(offset);
4757 parm_data->FileSize = cpu_to_le64(size);
4758 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004759 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4761 pSMB->InformationLevel =
4762 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4763 else
4764 pSMB->InformationLevel =
4765 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004766 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4768 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004769 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 else
4771 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004772 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 }
4774 pSMB->Reserved4 = 0;
4775 pSMB->hdr.smb_buf_length += byte_count;
4776 pSMB->ByteCount = cpu_to_le16(byte_count);
4777 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4778 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4779 if (rc) {
4780 cFYI(1,
4781 ("Send error in SetFileInfo (SetFileSize) = %d",
4782 rc));
4783 }
4784
4785 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004786 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787
Steve French50c2f752007-07-13 00:33:32 +00004788 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 since file handle passed in no longer valid */
4790
4791 return rc;
4792}
4793
Steve French50c2f752007-07-13 00:33:32 +00004794/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 an open handle, rather than by pathname - this is awkward due to
4796 potential access conflicts on the open, but it is unavoidable for these
4797 old servers since the only other choice is to go from 100 nanosecond DCE
4798 time and resort to the original setpathinfo level which takes the ancient
4799 DOS time format with 2 second granularity */
4800int
Steve French50c2f752007-07-13 00:33:32 +00004801CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4802 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803{
4804 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4805 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4806 char *data_offset;
4807 int rc = 0;
4808 int bytes_returned = 0;
4809 __u16 params, param_offset, offset, byte_count, count;
4810
4811 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004812 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4813
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 if (rc)
4815 return rc;
4816
Steve Frenchcd634992005-04-28 22:41:10 -07004817 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4818
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 /* At this point there is no need to override the current pid
4820 with the pid of the opener, but that could change if we someday
4821 use an existing handle (rather than opening one on the fly) */
4822 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4823 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004824
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825 params = 6;
4826 pSMB->MaxSetupCount = 0;
4827 pSMB->Reserved = 0;
4828 pSMB->Flags = 0;
4829 pSMB->Timeout = 0;
4830 pSMB->Reserved2 = 0;
4831 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4832 offset = param_offset + params;
4833
Steve French50c2f752007-07-13 00:33:32 +00004834 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835
Steve French26f57362007-08-30 22:09:15 +00004836 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 pSMB->MaxParameterCount = cpu_to_le16(2);
4838 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4839 pSMB->SetupCount = 1;
4840 pSMB->Reserved3 = 0;
4841 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4842 byte_count = 3 /* pad */ + params + count;
4843 pSMB->DataCount = cpu_to_le16(count);
4844 pSMB->ParameterCount = cpu_to_le16(params);
4845 pSMB->TotalDataCount = pSMB->DataCount;
4846 pSMB->TotalParameterCount = pSMB->ParameterCount;
4847 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4848 pSMB->DataOffset = cpu_to_le16(offset);
4849 pSMB->Fid = fid;
4850 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4851 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4852 else
4853 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4854 pSMB->Reserved4 = 0;
4855 pSMB->hdr.smb_buf_length += byte_count;
4856 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004857 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4859 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4860 if (rc) {
Steve French50c2f752007-07-13 00:33:32 +00004861 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 }
4863
Steve Frenchcd634992005-04-28 22:41:10 -07004864 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865
Steve French50c2f752007-07-13 00:33:32 +00004866 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 since file handle passed in no longer valid */
4868
4869 return rc;
4870}
4871
4872
4873int
4874CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004875 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004876 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877{
4878 TRANSACTION2_SPI_REQ *pSMB = NULL;
4879 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4880 int name_len;
4881 int rc = 0;
4882 int bytes_returned = 0;
4883 char *data_offset;
4884 __u16 params, param_offset, offset, byte_count, count;
4885
4886 cFYI(1, ("In SetTimes"));
4887
4888SetTimesRetry:
4889 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4890 (void **) &pSMBr);
4891 if (rc)
4892 return rc;
4893
4894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4895 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004896 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004897 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 name_len++; /* trailing null */
4899 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004900 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 name_len = strnlen(fileName, PATH_MAX);
4902 name_len++; /* trailing null */
4903 strncpy(pSMB->FileName, fileName, name_len);
4904 }
4905
4906 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004907 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 pSMB->MaxParameterCount = cpu_to_le16(2);
4909 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4910 pSMB->MaxSetupCount = 0;
4911 pSMB->Reserved = 0;
4912 pSMB->Flags = 0;
4913 pSMB->Timeout = 0;
4914 pSMB->Reserved2 = 0;
4915 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004916 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 offset = param_offset + params;
4918 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4919 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4920 pSMB->DataOffset = cpu_to_le16(offset);
4921 pSMB->SetupCount = 1;
4922 pSMB->Reserved3 = 0;
4923 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4924 byte_count = 3 /* pad */ + params + count;
4925
4926 pSMB->DataCount = cpu_to_le16(count);
4927 pSMB->ParameterCount = cpu_to_le16(params);
4928 pSMB->TotalDataCount = pSMB->DataCount;
4929 pSMB->TotalParameterCount = pSMB->ParameterCount;
4930 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4931 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4932 else
4933 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4934 pSMB->Reserved4 = 0;
4935 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004936 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 pSMB->ByteCount = cpu_to_le16(byte_count);
4938 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4939 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4940 if (rc) {
4941 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4942 }
4943
4944 cifs_buf_release(pSMB);
4945
4946 if (rc == -EAGAIN)
4947 goto SetTimesRetry;
4948
4949 return rc;
4950}
4951
4952/* Can not be used to set time stamps yet (due to old DOS time format) */
4953/* Can be used to set attributes */
4954#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4955 handling it anyway and NT4 was what we thought it would be needed for
4956 Do not delete it until we prove whether needed for Win9x though */
4957int
4958CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4959 __u16 dos_attrs, const struct nls_table *nls_codepage)
4960{
4961 SETATTR_REQ *pSMB = NULL;
4962 SETATTR_RSP *pSMBr = NULL;
4963 int rc = 0;
4964 int bytes_returned;
4965 int name_len;
4966
4967 cFYI(1, ("In SetAttrLegacy"));
4968
4969SetAttrLgcyRetry:
4970 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4971 (void **) &pSMBr);
4972 if (rc)
4973 return rc;
4974
4975 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4976 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004977 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 PATH_MAX, nls_codepage);
4979 name_len++; /* trailing null */
4980 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004981 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982 name_len = strnlen(fileName, PATH_MAX);
4983 name_len++; /* trailing null */
4984 strncpy(pSMB->fileName, fileName, name_len);
4985 }
4986 pSMB->attr = cpu_to_le16(dos_attrs);
4987 pSMB->BufferFormat = 0x04;
4988 pSMB->hdr.smb_buf_length += name_len + 1;
4989 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4990 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4991 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4992 if (rc) {
4993 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4994 }
4995
4996 cifs_buf_release(pSMB);
4997
4998 if (rc == -EAGAIN)
4999 goto SetAttrLgcyRetry;
5000
5001 return rc;
5002}
5003#endif /* temporarily unneeded SetAttr legacy function */
5004
5005int
5006CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00005007 char *fileName, __u64 mode, __u64 uid, __u64 gid,
5008 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07005009 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010{
5011 TRANSACTION2_SPI_REQ *pSMB = NULL;
5012 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5013 int name_len;
5014 int rc = 0;
5015 int bytes_returned = 0;
5016 FILE_UNIX_BASIC_INFO *data_offset;
5017 __u16 params, param_offset, offset, count, byte_count;
5018
5019 cFYI(1, ("In SetUID/GID/Mode"));
5020setPermsRetry:
5021 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5022 (void **) &pSMBr);
5023 if (rc)
5024 return rc;
5025
5026 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5027 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005028 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005029 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030 name_len++; /* trailing null */
5031 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005032 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 name_len = strnlen(fileName, PATH_MAX);
5034 name_len++; /* trailing null */
5035 strncpy(pSMB->FileName, fileName, name_len);
5036 }
5037
5038 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005039 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040 pSMB->MaxParameterCount = cpu_to_le16(2);
5041 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5042 pSMB->MaxSetupCount = 0;
5043 pSMB->Reserved = 0;
5044 pSMB->Flags = 0;
5045 pSMB->Timeout = 0;
5046 pSMB->Reserved2 = 0;
5047 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005048 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 offset = param_offset + params;
5050 data_offset =
5051 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5052 offset);
5053 memset(data_offset, 0, count);
5054 pSMB->DataOffset = cpu_to_le16(offset);
5055 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5056 pSMB->SetupCount = 1;
5057 pSMB->Reserved3 = 0;
5058 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5059 byte_count = 3 /* pad */ + params + count;
5060 pSMB->ParameterCount = cpu_to_le16(params);
5061 pSMB->DataCount = cpu_to_le16(count);
5062 pSMB->TotalParameterCount = pSMB->ParameterCount;
5063 pSMB->TotalDataCount = pSMB->DataCount;
5064 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5065 pSMB->Reserved4 = 0;
5066 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005067 /* Samba server ignores set of file size to zero due to bugs in some
5068 older clients, but we should be precise - we use SetFileSize to
5069 set file size and do not want to truncate file size to zero
5070 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005071 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005072 data_offset->EndOfFile = NO_CHANGE_64;
5073 data_offset->NumOfBytes = NO_CHANGE_64;
5074 data_offset->LastStatusChange = NO_CHANGE_64;
5075 data_offset->LastAccessTime = NO_CHANGE_64;
5076 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 data_offset->Uid = cpu_to_le64(uid);
5078 data_offset->Gid = cpu_to_le64(gid);
5079 /* better to leave device as zero when it is */
5080 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5081 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5082 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005083
Steve French790fe572007-07-07 19:25:05 +00005084 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005086 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005088 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005090 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005092 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005094 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005096 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5098
5099
5100 pSMB->ByteCount = cpu_to_le16(byte_count);
5101 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5102 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5103 if (rc) {
5104 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5105 }
5106
5107 if (pSMB)
5108 cifs_buf_release(pSMB);
5109 if (rc == -EAGAIN)
5110 goto setPermsRetry;
5111 return rc;
5112}
5113
Steve French50c2f752007-07-13 00:33:32 +00005114int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005115 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005116 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005117 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118{
5119 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005120 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5121 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005122 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 int bytes_returned;
5124
Steve French50c2f752007-07-13 00:33:32 +00005125 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005127 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 if (rc)
5129 return rc;
5130
5131 pSMB->TotalParameterCount = 0 ;
5132 pSMB->TotalDataCount = 0;
5133 pSMB->MaxParameterCount = cpu_to_le32(2);
5134 /* BB find exact data count max from sess structure BB */
5135 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005136/* BB VERIFY verify which is correct for above BB */
5137 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5138 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5139
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 pSMB->MaxSetupCount = 4;
5141 pSMB->Reserved = 0;
5142 pSMB->ParameterOffset = 0;
5143 pSMB->DataCount = 0;
5144 pSMB->DataOffset = 0;
5145 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5146 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5147 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005148 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5150 pSMB->Reserved2 = 0;
5151 pSMB->CompletionFilter = cpu_to_le32(filter);
5152 pSMB->Fid = netfid; /* file handle always le */
5153 pSMB->ByteCount = 0;
5154
5155 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5156 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5157 if (rc) {
5158 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005159 } else {
5160 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005161 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005162 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005163 sizeof(struct dir_notify_req),
5164 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005165 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005166 dnotify_req->Pid = pSMB->hdr.Pid;
5167 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5168 dnotify_req->Mid = pSMB->hdr.Mid;
5169 dnotify_req->Tid = pSMB->hdr.Tid;
5170 dnotify_req->Uid = pSMB->hdr.Uid;
5171 dnotify_req->netfid = netfid;
5172 dnotify_req->pfile = pfile;
5173 dnotify_req->filter = filter;
5174 dnotify_req->multishot = multishot;
5175 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005176 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005177 &GlobalDnotifyReqList);
5178 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005179 } else
Steve French47c786e2005-10-11 20:03:18 -07005180 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181 }
5182 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005183 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184}
5185#ifdef CONFIG_CIFS_XATTR
5186ssize_t
5187CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5188 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005189 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005190 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191{
5192 /* BB assumes one setup word */
5193 TRANSACTION2_QPI_REQ *pSMB = NULL;
5194 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5195 int rc = 0;
5196 int bytes_returned;
5197 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005198 struct fea *temp_fea;
5199 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 __u16 params, byte_count;
5201
5202 cFYI(1, ("In Query All EAs path %s", searchName));
5203QAllEAsRetry:
5204 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5205 (void **) &pSMBr);
5206 if (rc)
5207 return rc;
5208
5209 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5210 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005211 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005212 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 name_len++; /* trailing null */
5214 name_len *= 2;
5215 } else { /* BB improve the check for buffer overruns BB */
5216 name_len = strnlen(searchName, PATH_MAX);
5217 name_len++; /* trailing null */
5218 strncpy(pSMB->FileName, searchName, name_len);
5219 }
5220
Steve French50c2f752007-07-13 00:33:32 +00005221 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 pSMB->TotalDataCount = 0;
5223 pSMB->MaxParameterCount = cpu_to_le16(2);
5224 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5225 pSMB->MaxSetupCount = 0;
5226 pSMB->Reserved = 0;
5227 pSMB->Flags = 0;
5228 pSMB->Timeout = 0;
5229 pSMB->Reserved2 = 0;
5230 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005231 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 pSMB->DataCount = 0;
5233 pSMB->DataOffset = 0;
5234 pSMB->SetupCount = 1;
5235 pSMB->Reserved3 = 0;
5236 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5237 byte_count = params + 1 /* pad */ ;
5238 pSMB->TotalParameterCount = cpu_to_le16(params);
5239 pSMB->ParameterCount = pSMB->TotalParameterCount;
5240 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5241 pSMB->Reserved4 = 0;
5242 pSMB->hdr.smb_buf_length += byte_count;
5243 pSMB->ByteCount = cpu_to_le16(byte_count);
5244
5245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5246 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5247 if (rc) {
5248 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5249 } else { /* decode response */
5250 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5251
5252 /* BB also check enough total bytes returned */
5253 /* BB we need to improve the validity checking
5254 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005255 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 rc = -EIO; /* bad smb */
5257 /* else if (pFindData){
5258 memcpy((char *) pFindData,
5259 (char *) &pSMBr->hdr.Protocol +
5260 data_offset, kl);
5261 }*/ else {
5262 /* check that length of list is not more than bcc */
5263 /* check that each entry does not go beyond length
5264 of list */
5265 /* check that each element of each entry does not
5266 go beyond end of list */
5267 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005268 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269 rc = 0;
5270 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005271 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 ea_response_data = (struct fealist *)
5273 (((char *) &pSMBr->hdr.Protocol) +
5274 data_offset);
5275 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005276 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005277 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005279 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 } else {
5281 /* account for ea list len */
5282 name_len -= 4;
5283 temp_fea = ea_response_data->list;
5284 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005285 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 __u16 value_len;
5287 name_len -= 4;
5288 temp_ptr += 4;
5289 rc += temp_fea->name_len;
5290 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005291 rc = rc + 5 + 1;
5292 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005293 memcpy(EAData, "user.", 5);
5294 EAData += 5;
5295 memcpy(EAData, temp_ptr,
5296 temp_fea->name_len);
5297 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 /* null terminate name */
5299 *EAData = 0;
5300 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005301 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302 /* skip copy - calc size only */
5303 } else {
5304 /* stop before overrun buffer */
5305 rc = -ERANGE;
5306 break;
5307 }
5308 name_len -= temp_fea->name_len;
5309 temp_ptr += temp_fea->name_len;
5310 /* account for trailing null */
5311 name_len--;
5312 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005313 value_len =
5314 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 name_len -= value_len;
5316 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005317 /* BB check that temp_ptr is still
5318 within the SMB BB*/
5319
5320 /* no trailing null to account for
5321 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322 /* go on to next EA */
5323 temp_fea = (struct fea *)temp_ptr;
5324 }
5325 }
5326 }
5327 }
5328 if (pSMB)
5329 cifs_buf_release(pSMB);
5330 if (rc == -EAGAIN)
5331 goto QAllEAsRetry;
5332
5333 return (ssize_t)rc;
5334}
5335
Steve French50c2f752007-07-13 00:33:32 +00005336ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5337 const unsigned char *searchName, const unsigned char *ea_name,
5338 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005339 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340{
5341 TRANSACTION2_QPI_REQ *pSMB = NULL;
5342 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5343 int rc = 0;
5344 int bytes_returned;
5345 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005346 struct fea *temp_fea;
5347 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348 __u16 params, byte_count;
5349
5350 cFYI(1, ("In Query EA path %s", searchName));
5351QEARetry:
5352 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5353 (void **) &pSMBr);
5354 if (rc)
5355 return rc;
5356
5357 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5358 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005359 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005360 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 name_len++; /* trailing null */
5362 name_len *= 2;
5363 } else { /* BB improve the check for buffer overruns BB */
5364 name_len = strnlen(searchName, PATH_MAX);
5365 name_len++; /* trailing null */
5366 strncpy(pSMB->FileName, searchName, name_len);
5367 }
5368
Steve French50c2f752007-07-13 00:33:32 +00005369 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 pSMB->TotalDataCount = 0;
5371 pSMB->MaxParameterCount = cpu_to_le16(2);
5372 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5373 pSMB->MaxSetupCount = 0;
5374 pSMB->Reserved = 0;
5375 pSMB->Flags = 0;
5376 pSMB->Timeout = 0;
5377 pSMB->Reserved2 = 0;
5378 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005379 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 pSMB->DataCount = 0;
5381 pSMB->DataOffset = 0;
5382 pSMB->SetupCount = 1;
5383 pSMB->Reserved3 = 0;
5384 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5385 byte_count = params + 1 /* pad */ ;
5386 pSMB->TotalParameterCount = cpu_to_le16(params);
5387 pSMB->ParameterCount = pSMB->TotalParameterCount;
5388 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5389 pSMB->Reserved4 = 0;
5390 pSMB->hdr.smb_buf_length += byte_count;
5391 pSMB->ByteCount = cpu_to_le16(byte_count);
5392
5393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5395 if (rc) {
5396 cFYI(1, ("Send error in Query EA = %d", rc));
5397 } else { /* decode response */
5398 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5399
5400 /* BB also check enough total bytes returned */
5401 /* BB we need to improve the validity checking
5402 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005403 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 rc = -EIO; /* bad smb */
5405 /* else if (pFindData){
5406 memcpy((char *) pFindData,
5407 (char *) &pSMBr->hdr.Protocol +
5408 data_offset, kl);
5409 }*/ else {
5410 /* check that length of list is not more than bcc */
5411 /* check that each entry does not go beyond length
5412 of list */
5413 /* check that each element of each entry does not
5414 go beyond end of list */
5415 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005416 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 rc = -ENODATA;
5418 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005419 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 ea_response_data = (struct fealist *)
5421 (((char *) &pSMBr->hdr.Protocol) +
5422 data_offset);
5423 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005424 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005425 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005427 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 } else {
5429 /* account for ea list len */
5430 name_len -= 4;
5431 temp_fea = ea_response_data->list;
5432 temp_ptr = (char *)temp_fea;
5433 /* loop through checking if we have a matching
5434 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005435 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 __u16 value_len;
5437 name_len -= 4;
5438 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005439 value_len =
5440 le16_to_cpu(temp_fea->value_len);
5441 /* BB validate that value_len falls within SMB,
5442 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005443 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444 temp_fea->name_len) == 0) {
5445 /* found a match */
5446 rc = value_len;
5447 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005448 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 memcpy(ea_value,
5450 temp_fea->name+temp_fea->name_len+1,
5451 rc);
Steve French50c2f752007-07-13 00:33:32 +00005452 /* ea values, unlike ea
5453 names, are not null
5454 terminated */
Steve French790fe572007-07-07 19:25:05 +00005455 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 /* skip copy - calc size only */
5457 } else {
Steve French50c2f752007-07-13 00:33:32 +00005458 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 rc = -ERANGE;
5460 }
5461 break;
5462 }
5463 name_len -= temp_fea->name_len;
5464 temp_ptr += temp_fea->name_len;
5465 /* account for trailing null */
5466 name_len--;
5467 temp_ptr++;
5468 name_len -= value_len;
5469 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005470 /* No trailing null to account for in
5471 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 temp_fea = (struct fea *)temp_ptr;
5473 }
Steve French50c2f752007-07-13 00:33:32 +00005474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 }
5476 }
5477 if (pSMB)
5478 cifs_buf_release(pSMB);
5479 if (rc == -EAGAIN)
5480 goto QEARetry;
5481
5482 return (ssize_t)rc;
5483}
5484
5485int
5486CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005487 const char *ea_name, const void *ea_value,
5488 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5489 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490{
5491 struct smb_com_transaction2_spi_req *pSMB = NULL;
5492 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5493 struct fealist *parm_data;
5494 int name_len;
5495 int rc = 0;
5496 int bytes_returned = 0;
5497 __u16 params, param_offset, byte_count, offset, count;
5498
5499 cFYI(1, ("In SetEA"));
5500SetEARetry:
5501 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5502 (void **) &pSMBr);
5503 if (rc)
5504 return rc;
5505
5506 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5507 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005508 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005509 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 name_len++; /* trailing null */
5511 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005512 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 name_len = strnlen(fileName, PATH_MAX);
5514 name_len++; /* trailing null */
5515 strncpy(pSMB->FileName, fileName, name_len);
5516 }
5517
5518 params = 6 + name_len;
5519
5520 /* done calculating parms using name_len of file name,
5521 now use name_len to calculate length of ea name
5522 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005523 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 name_len = 0;
5525 else
Steve French50c2f752007-07-13 00:33:32 +00005526 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527
5528 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5529 pSMB->MaxParameterCount = cpu_to_le16(2);
5530 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5531 pSMB->MaxSetupCount = 0;
5532 pSMB->Reserved = 0;
5533 pSMB->Flags = 0;
5534 pSMB->Timeout = 0;
5535 pSMB->Reserved2 = 0;
5536 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005537 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 offset = param_offset + params;
5539 pSMB->InformationLevel =
5540 cpu_to_le16(SMB_SET_FILE_EA);
5541
5542 parm_data =
5543 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5544 offset);
5545 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5546 pSMB->DataOffset = cpu_to_le16(offset);
5547 pSMB->SetupCount = 1;
5548 pSMB->Reserved3 = 0;
5549 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5550 byte_count = 3 /* pad */ + params + count;
5551 pSMB->DataCount = cpu_to_le16(count);
5552 parm_data->list_len = cpu_to_le32(count);
5553 parm_data->list[0].EA_flags = 0;
5554 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005555 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005557 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005558 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 parm_data->list[0].name[name_len] = 0;
5560 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5561 /* caller ensures that ea_value_len is less than 64K but
5562 we need to ensure that it fits within the smb */
5563
Steve French50c2f752007-07-13 00:33:32 +00005564 /*BB add length check to see if it would fit in
5565 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005566 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5567 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005568 memcpy(parm_data->list[0].name+name_len+1,
5569 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570
5571 pSMB->TotalDataCount = pSMB->DataCount;
5572 pSMB->ParameterCount = cpu_to_le16(params);
5573 pSMB->TotalParameterCount = pSMB->ParameterCount;
5574 pSMB->Reserved4 = 0;
5575 pSMB->hdr.smb_buf_length += byte_count;
5576 pSMB->ByteCount = cpu_to_le16(byte_count);
5577 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5578 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5579 if (rc) {
5580 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5581 }
5582
5583 cifs_buf_release(pSMB);
5584
5585 if (rc == -EAGAIN)
5586 goto SetEARetry;
5587
5588 return rc;
5589}
5590
5591#endif