blob: 46c2bb455124a10c93599d66a7af893211ec4f1a [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"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
Steve Frencheeac8042006-01-13 21:34:58 -080040#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
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);
441 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000442 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French50c2f752007-07-13 00:33:32 +0000443
Steve French39798772006-05-31 22:40:51 +0000444 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000445 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000446 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
447 count += strlen(protocols[i].name) + 1;
448 /* null at end of source and target buffers anyway */
449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 pSMB->hdr.smb_buf_length += count;
451 pSMB->ByteCount = cpu_to_le16(count);
452
453 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
454 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000455 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000456 goto neg_err_exit;
457
Al Viro733f99a2006-10-14 16:48:26 +0100458 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000459 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000460 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000461 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000462 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000463 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000464 could not negotiate a common dialect */
465 rc = -EOPNOTSUPP;
466 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000467#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000468 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100469 && ((dialect == LANMAN_PROT)
470 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000471 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000472 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000473
Steve French790fe572007-07-07 19:25:05 +0000474 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000475 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000476 server->secType = LANMAN;
477 else {
478 cERROR(1, ("mount failed weak security disabled"
479 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000480 rc = -EOPNOTSUPP;
481 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000482 }
Steve French254e55e2006-06-04 05:53:15 +0000483 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
484 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
485 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000486 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000487 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
488 /* even though we do not use raw we might as well set this
489 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000490 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000491 server->maxRw = 0xFF00;
492 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
493 } else {
494 server->maxRw = 0;/* we do not need to use raw anyway */
495 server->capabilities = CAP_MPX_MODE;
496 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000497 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000498 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000499 /* OS/2 often does not set timezone therefore
500 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000501 * Could deviate slightly from the right zone.
502 * Smallest defined timezone difference is 15 minutes
503 * (i.e. Nepal). Rounding up/down is done to match
504 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000505 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000506 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000507 struct timespec ts, utc;
508 utc = CURRENT_TIME;
509 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
510 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000511 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
512 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000513 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000514 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000515 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000516 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000517 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000518 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000519 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000520 if (val < 0)
Steve Frenchb815f1e2006-10-02 05:53:29 +0000521 result = - result;
522 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000523 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000524 server->timeAdj = (int)tmp;
525 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000526 }
Steve French790fe572007-07-07 19:25:05 +0000527 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000528
Steve French39798772006-05-31 22:40:51 +0000529
Steve French254e55e2006-06-04 05:53:15 +0000530 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000531 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000532
Steve French50c2f752007-07-13 00:33:32 +0000533 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000534 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000535 memcpy(server->cryptKey, rsp->EncryptionKey,
536 CIFS_CRYPTO_KEY_SIZE);
537 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
538 rc = -EIO; /* need cryptkey unless plain text */
539 goto neg_err_exit;
540 }
Steve French39798772006-05-31 22:40:51 +0000541
Steve French790fe572007-07-07 19:25:05 +0000542 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000543 /* we will not end up setting signing flags - as no signing
544 was in LANMAN and server did not return the flags on */
545 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000546#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000547 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000548 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000549 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000550 rc = -EOPNOTSUPP;
551#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000552 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000553 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000554 /* unknown wct */
555 rc = -EOPNOTSUPP;
556 goto neg_err_exit;
557 }
558 /* else wct == 17 NTLM */
559 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000560 if ((server->secMode & SECMODE_USER) == 0)
561 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000562
Steve French790fe572007-07-07 19:25:05 +0000563 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000564#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000565 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000566#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000567 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000568 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000569
Steve French790fe572007-07-07 19:25:05 +0000570 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000571 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000572 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000573 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000574 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000575 server->secType = NTLMv2;
576 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000577
Steve French254e55e2006-06-04 05:53:15 +0000578 /* one byte, so no need to convert this or EncryptionKeyLen from
579 little endian */
580 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
581 /* probably no need to store and check maxvcs */
582 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000584 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
585 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
586 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
587 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000588 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
589 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000590 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
591 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
592 CIFS_CRYPTO_KEY_SIZE);
593 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
594 && (pSMBr->EncryptionKeyLength == 0)) {
595 /* decode security blob */
596 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
597 rc = -EIO; /* no crypt key only if plain text pwd */
598 goto neg_err_exit;
599 }
600
601 /* BB might be helpful to save off the domain of server here */
602
Steve French50c2f752007-07-13 00:33:32 +0000603 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000604 (server->capabilities & CAP_EXTENDED_SECURITY)) {
605 count = pSMBr->ByteCount;
606 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000608 else if (count == 16) {
609 server->secType = RawNTLMSSP;
610 if (server->socketUseCount.counter > 1) {
611 if (memcmp(server->server_GUID,
612 pSMBr->u.extended_response.
613 GUID, 16) != 0) {
614 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000616 pSMBr->u.extended_response.GUID,
617 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 }
Steve French254e55e2006-06-04 05:53:15 +0000619 } else
620 memcpy(server->server_GUID,
621 pSMBr->u.extended_response.GUID, 16);
622 } else {
623 rc = decode_negTokenInit(pSMBr->u.extended_response.
624 SecurityBlob,
625 count - 16,
626 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000627 if (rc == 1) {
Steve French254e55e2006-06-04 05:53:15 +0000628 /* BB Need to fill struct for sessetup here */
629 rc = -EOPNOTSUPP;
630 } else {
631 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 }
Steve French254e55e2006-06-04 05:53:15 +0000634 } else
635 server->capabilities &= ~CAP_EXTENDED_SECURITY;
636
Steve French6344a422006-06-12 04:18:35 +0000637#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000638signing_check:
Steve French6344a422006-06-12 04:18:35 +0000639#endif
Steve French762e5ab2007-06-28 18:41:42 +0000640 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
641 /* MUST_SIGN already includes the MAY_SIGN FLAG
642 so if this is zero it means that signing is disabled */
643 cFYI(1, ("Signing disabled"));
Steve French790fe572007-07-07 19:25:05 +0000644 if (server->secMode & SECMODE_SIGN_REQUIRED)
Steve French762e5ab2007-06-28 18:41:42 +0000645 cERROR(1, ("Server requires "
646 "/proc/fs/cifs/PacketSigningEnabled "
647 "to be on"));
Steve French50c2f752007-07-13 00:33:32 +0000648 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000649 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000650 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
651 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000652 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000653 if ((server->secMode &
654 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
655 cERROR(1,
656 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000657 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000658 } else
659 server->secMode |= SECMODE_SIGN_REQUIRED;
660 } else {
661 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000662 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000663 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000664 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 }
Steve French50c2f752007-07-13 00:33:32 +0000666
667neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700668 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000669
Steve French790fe572007-07-07 19:25:05 +0000670 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 return rc;
672}
673
674int
675CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
676{
677 struct smb_hdr *smb_buffer;
678 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
679 int rc = 0;
680 int length;
681
682 cFYI(1, ("In tree disconnect"));
683 /*
684 * If last user of the connection and
685 * connection alive - disconnect it
686 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000687 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 * to be freed and kernel thread woken up).
689 */
690 if (tcon)
691 down(&tcon->tconSem);
692 else
693 return -EIO;
694
695 atomic_dec(&tcon->useCount);
696 if (atomic_read(&tcon->useCount) > 0) {
697 up(&tcon->tconSem);
698 return -EBUSY;
699 }
700
Steve French50c2f752007-07-13 00:33:32 +0000701 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000703 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000705 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 }
707
Steve French790fe572007-07-07 19:25:05 +0000708 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 up(&tcon->tconSem);
710 return -EIO;
711 }
Steve French50c2f752007-07-13 00:33:32 +0000712 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700713 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 if (rc) {
715 up(&tcon->tconSem);
716 return rc;
717 } else {
718 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
721 &length, 0);
722 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700723 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 if (smb_buffer)
726 cifs_small_buf_release(smb_buffer);
727 up(&tcon->tconSem);
728
Steve French50c2f752007-07-13 00:33:32 +0000729 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 closed on server already e.g. due to tcp session crashing */
731 if (rc == -EAGAIN)
732 rc = 0;
733
734 return rc;
735}
736
737int
738CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
739{
740 struct smb_hdr *smb_buffer_response;
741 LOGOFF_ANDX_REQ *pSMB;
742 int rc = 0;
743 int length;
744
745 cFYI(1, ("In SMBLogoff for session disconnect"));
746 if (ses)
747 down(&ses->sesSem);
748 else
749 return -EIO;
750
751 atomic_dec(&ses->inUse);
752 if (atomic_read(&ses->inUse) > 0) {
753 up(&ses->sesSem);
754 return -EBUSY;
755 }
756 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
757 if (rc) {
758 up(&ses->sesSem);
759 return rc;
760 }
761
762 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
Steve French50c2f752007-07-13 00:33:32 +0000763
Steve French790fe572007-07-07 19:25:05 +0000764 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700765 pSMB->hdr.Mid = GetNextMid(ses->server);
766
Steve French790fe572007-07-07 19:25:05 +0000767 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
769 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
770 }
771
772 pSMB->hdr.Uid = ses->Suid;
773
774 pSMB->AndXCommand = 0xFF;
775 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
776 smb_buffer_response, &length, 0);
777 if (ses->server) {
778 atomic_dec(&ses->server->socketUseCount);
779 if (atomic_read(&ses->server->socketUseCount) == 0) {
780 spin_lock(&GlobalMid_Lock);
781 ses->server->tcpStatus = CifsExiting;
782 spin_unlock(&GlobalMid_Lock);
783 rc = -ESHUTDOWN;
784 }
785 }
Steve Frencha59c6582005-08-17 12:12:19 -0700786 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700787 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000790 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 error */
792 if (rc == -EAGAIN)
793 rc = 0;
794 return rc;
795}
796
797int
Steve French2d785a52007-07-15 01:48:57 +0000798CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
799 __u16 type, const struct nls_table *nls_codepage, int remap)
800{
801 TRANSACTION2_SPI_REQ *pSMB = NULL;
802 TRANSACTION2_SPI_RSP *pSMBr = NULL;
803 struct unlink_psx_rq *pRqD;
804 int name_len;
805 int rc = 0;
806 int bytes_returned = 0;
807 __u16 params, param_offset, offset, byte_count;
808
809 cFYI(1, ("In POSIX delete"));
810PsxDelete:
811 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
812 (void **) &pSMBr);
813 if (rc)
814 return rc;
815
816 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
817 name_len =
818 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
819 PATH_MAX, nls_codepage, remap);
820 name_len++; /* trailing null */
821 name_len *= 2;
822 } else { /* BB add path length overrun check */
823 name_len = strnlen(fileName, PATH_MAX);
824 name_len++; /* trailing null */
825 strncpy(pSMB->FileName, fileName, name_len);
826 }
827
828 params = 6 + name_len;
829 pSMB->MaxParameterCount = cpu_to_le16(2);
830 pSMB->MaxDataCount = 0; /* BB double check this with jra */
831 pSMB->MaxSetupCount = 0;
832 pSMB->Reserved = 0;
833 pSMB->Flags = 0;
834 pSMB->Timeout = 0;
835 pSMB->Reserved2 = 0;
836 param_offset = offsetof(struct smb_com_transaction2_spi_req,
837 InformationLevel) - 4;
838 offset = param_offset + params;
839
840 /* Setup pointer to Request Data (inode type) */
841 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
842 pRqD->type = cpu_to_le16(type);
843 pSMB->ParameterOffset = cpu_to_le16(param_offset);
844 pSMB->DataOffset = cpu_to_le16(offset);
845 pSMB->SetupCount = 1;
846 pSMB->Reserved3 = 0;
847 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
848 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
849
850 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
851 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
852 pSMB->ParameterCount = cpu_to_le16(params);
853 pSMB->TotalParameterCount = pSMB->ParameterCount;
854 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
855 pSMB->Reserved4 = 0;
856 pSMB->hdr.smb_buf_length += byte_count;
857 pSMB->ByteCount = cpu_to_le16(byte_count);
858 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
859 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
860 if (rc) {
861 cFYI(1, ("Posix delete returned %d", rc));
862 }
863 cifs_buf_release(pSMB);
864
865 cifs_stats_inc(&tcon->num_deletes);
866
867 if (rc == -EAGAIN)
868 goto PsxDelete;
869
870 return rc;
871}
872
873int
Steve French737b7582005-04-28 22:41:06 -0700874CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
875 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
877 DELETE_FILE_REQ *pSMB = NULL;
878 DELETE_FILE_RSP *pSMBr = NULL;
879 int rc = 0;
880 int bytes_returned;
881 int name_len;
882
883DelFileRetry:
884 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
885 (void **) &pSMBr);
886 if (rc)
887 return rc;
888
889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
890 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000891 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700892 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 name_len++; /* trailing null */
894 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700895 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 name_len = strnlen(fileName, PATH_MAX);
897 name_len++; /* trailing null */
898 strncpy(pSMB->fileName, fileName, name_len);
899 }
900 pSMB->SearchAttributes =
901 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
902 pSMB->BufferFormat = 0x04;
903 pSMB->hdr.smb_buf_length += name_len + 1;
904 pSMB->ByteCount = cpu_to_le16(name_len + 1);
905 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
906 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700907 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (rc) {
909 cFYI(1, ("Error in RMFile = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000910 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
912 cifs_buf_release(pSMB);
913 if (rc == -EAGAIN)
914 goto DelFileRetry;
915
916 return rc;
917}
918
919int
Steve French50c2f752007-07-13 00:33:32 +0000920CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700921 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922{
923 DELETE_DIRECTORY_REQ *pSMB = NULL;
924 DELETE_DIRECTORY_RSP *pSMBr = NULL;
925 int rc = 0;
926 int bytes_returned;
927 int name_len;
928
929 cFYI(1, ("In CIFSSMBRmDir"));
930RmDirRetry:
931 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
932 (void **) &pSMBr);
933 if (rc)
934 return rc;
935
936 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700937 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
938 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 name_len++; /* trailing null */
940 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700941 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 name_len = strnlen(dirName, PATH_MAX);
943 name_len++; /* trailing null */
944 strncpy(pSMB->DirName, dirName, name_len);
945 }
946
947 pSMB->BufferFormat = 0x04;
948 pSMB->hdr.smb_buf_length += name_len + 1;
949 pSMB->ByteCount = cpu_to_le16(name_len + 1);
950 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
951 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700952 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 if (rc) {
954 cFYI(1, ("Error in RMDir = %d", rc));
955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
957 cifs_buf_release(pSMB);
958 if (rc == -EAGAIN)
959 goto RmDirRetry;
960 return rc;
961}
962
963int
964CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700965 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966{
967 int rc = 0;
968 CREATE_DIRECTORY_REQ *pSMB = NULL;
969 CREATE_DIRECTORY_RSP *pSMBr = NULL;
970 int bytes_returned;
971 int name_len;
972
973 cFYI(1, ("In CIFSSMBMkDir"));
974MkDirRetry:
975 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
976 (void **) &pSMBr);
977 if (rc)
978 return rc;
979
980 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000981 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700982 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 name_len++; /* trailing null */
984 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700985 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 name_len = strnlen(name, PATH_MAX);
987 name_len++; /* trailing null */
988 strncpy(pSMB->DirName, name, name_len);
989 }
990
991 pSMB->BufferFormat = 0x04;
992 pSMB->hdr.smb_buf_length += name_len + 1;
993 pSMB->ByteCount = cpu_to_le16(name_len + 1);
994 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
995 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700996 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 if (rc) {
998 cFYI(1, ("Error in Mkdir = %d", rc));
999 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 cifs_buf_release(pSMB);
1002 if (rc == -EAGAIN)
1003 goto MkDirRetry;
1004 return rc;
1005}
1006
Steve French2dd29d32007-04-23 22:07:35 +00001007int
1008CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1009 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001010 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001011 const struct nls_table *nls_codepage, int remap)
1012{
1013 TRANSACTION2_SPI_REQ *pSMB = NULL;
1014 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1015 int name_len;
1016 int rc = 0;
1017 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001018 __u16 params, param_offset, offset, byte_count, count;
1019 OPEN_PSX_REQ * pdata;
1020 OPEN_PSX_RSP * psx_rsp;
1021
1022 cFYI(1, ("In POSIX Create"));
1023PsxCreat:
1024 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1025 (void **) &pSMBr);
1026 if (rc)
1027 return rc;
1028
1029 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1030 name_len =
1031 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1032 PATH_MAX, nls_codepage, remap);
1033 name_len++; /* trailing null */
1034 name_len *= 2;
1035 } else { /* BB improve the check for buffer overruns BB */
1036 name_len = strnlen(name, PATH_MAX);
1037 name_len++; /* trailing null */
1038 strncpy(pSMB->FileName, name, name_len);
1039 }
1040
1041 params = 6 + name_len;
1042 count = sizeof(OPEN_PSX_REQ);
1043 pSMB->MaxParameterCount = cpu_to_le16(2);
1044 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1045 pSMB->MaxSetupCount = 0;
1046 pSMB->Reserved = 0;
1047 pSMB->Flags = 0;
1048 pSMB->Timeout = 0;
1049 pSMB->Reserved2 = 0;
1050 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001051 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001052 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001053 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1054 pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
1055 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001056 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001057 pdata->OpenFlags = cpu_to_le32(*pOplock);
1058 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1059 pSMB->DataOffset = cpu_to_le16(offset);
1060 pSMB->SetupCount = 1;
1061 pSMB->Reserved3 = 0;
1062 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1063 byte_count = 3 /* pad */ + params + count;
1064
1065 pSMB->DataCount = cpu_to_le16(count);
1066 pSMB->ParameterCount = cpu_to_le16(params);
1067 pSMB->TotalDataCount = pSMB->DataCount;
1068 pSMB->TotalParameterCount = pSMB->ParameterCount;
1069 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1070 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001071 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001072 pSMB->ByteCount = cpu_to_le16(byte_count);
1073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1075 if (rc) {
1076 cFYI(1, ("Posix create returned %d", rc));
1077 goto psx_create_err;
1078 }
1079
Steve French790fe572007-07-07 19:25:05 +00001080 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001081 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1082
1083 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1084 rc = -EIO; /* bad smb */
1085 goto psx_create_err;
1086 }
1087
1088 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001089 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001090 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001091
Steve French2dd29d32007-04-23 22:07:35 +00001092 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001093 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001094 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1095 /* Let caller know file was created so we can set the mode. */
1096 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001097 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001098 *pOplock |= CIFS_CREATE_ACTION;
1099 /* check to make sure response data is there */
Steve French790fe572007-07-07 19:25:05 +00001100 if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001101 pRetData->Type = -1; /* unknown */
1102#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001103 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001104#endif
1105 } else {
Steve French790fe572007-07-07 19:25:05 +00001106 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001107 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001108 cERROR(1, ("Open response data too small"));
Steve French2dd29d32007-04-23 22:07:35 +00001109 pRetData->Type = -1;
1110 goto psx_create_err;
1111 }
Steve French50c2f752007-07-13 00:33:32 +00001112 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001113 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001114 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001115 }
Steve French2dd29d32007-04-23 22:07:35 +00001116
1117psx_create_err:
1118 cifs_buf_release(pSMB);
1119
1120 cifs_stats_inc(&tcon->num_mkdirs);
1121
1122 if (rc == -EAGAIN)
1123 goto PsxCreat;
1124
Steve French50c2f752007-07-13 00:33:32 +00001125 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001126}
1127
Steve Frencha9d02ad2005-08-24 23:06:05 -07001128static __u16 convert_disposition(int disposition)
1129{
1130 __u16 ofun = 0;
1131
1132 switch (disposition) {
1133 case FILE_SUPERSEDE:
1134 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1135 break;
1136 case FILE_OPEN:
1137 ofun = SMBOPEN_OAPPEND;
1138 break;
1139 case FILE_CREATE:
1140 ofun = SMBOPEN_OCREATE;
1141 break;
1142 case FILE_OPEN_IF:
1143 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1144 break;
1145 case FILE_OVERWRITE:
1146 ofun = SMBOPEN_OTRUNC;
1147 break;
1148 case FILE_OVERWRITE_IF:
1149 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1150 break;
1151 default:
Steve French790fe572007-07-07 19:25:05 +00001152 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001153 ofun = SMBOPEN_OAPPEND; /* regular open */
1154 }
1155 return ofun;
1156}
1157
1158int
1159SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1160 const char *fileName, const int openDisposition,
1161 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001162 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001163 const struct nls_table *nls_codepage, int remap)
1164{
1165 int rc = -EACCES;
1166 OPENX_REQ *pSMB = NULL;
1167 OPENX_RSP *pSMBr = NULL;
1168 int bytes_returned;
1169 int name_len;
1170 __u16 count;
1171
1172OldOpenRetry:
1173 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1174 (void **) &pSMBr);
1175 if (rc)
1176 return rc;
1177
1178 pSMB->AndXCommand = 0xFF; /* none */
1179
1180 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1181 count = 1; /* account for one byte pad to word boundary */
1182 name_len =
1183 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1184 fileName, PATH_MAX, nls_codepage, remap);
1185 name_len++; /* trailing null */
1186 name_len *= 2;
1187 } else { /* BB improve check for buffer overruns BB */
1188 count = 0; /* no pad */
1189 name_len = strnlen(fileName, PATH_MAX);
1190 name_len++; /* trailing null */
1191 strncpy(pSMB->fileName, fileName, name_len);
1192 }
1193 if (*pOplock & REQ_OPLOCK)
1194 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001195 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001196 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001197
Steve Frencha9d02ad2005-08-24 23:06:05 -07001198 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1199 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1200 /* 0 = read
1201 1 = write
1202 2 = rw
1203 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001204 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001205 pSMB->Mode = cpu_to_le16(2);
1206 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1207 /* set file as system file if special file such
1208 as fifo and server expecting SFU style and
1209 no Unix extensions */
1210
Steve French790fe572007-07-07 19:25:05 +00001211 if (create_options & CREATE_OPTION_SPECIAL)
1212 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1213 else
Steve French3e87d802005-09-18 20:49:21 -07001214 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001215
1216 /* if ((omode & S_IWUGO) == 0)
1217 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1218 /* Above line causes problems due to vfs splitting create into two
1219 pieces - need to set mode after file created not while it is
1220 being created */
1221
1222 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001223/* pSMB->CreateOptions = cpu_to_le32(create_options &
1224 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001225 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001226
1227 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001228 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229 count += name_len;
1230 pSMB->hdr.smb_buf_length += count;
1231
1232 pSMB->ByteCount = cpu_to_le16(count);
1233 /* long_op set to 1 to allow for oplock break timeouts */
1234 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00001235 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236 cifs_stats_inc(&tcon->num_opens);
1237 if (rc) {
1238 cFYI(1, ("Error in Open = %d", rc));
1239 } else {
1240 /* BB verify if wct == 15 */
1241
1242/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1243
1244 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1245 /* Let caller know file was created so we can set the mode. */
1246 /* Do we care about the CreateAction in any other cases? */
1247 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001248/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249 *pOplock |= CIFS_CREATE_ACTION; */
1250 /* BB FIXME END */
1251
Steve French790fe572007-07-07 19:25:05 +00001252 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1254 pfile_info->LastAccessTime = 0; /* BB fixme */
1255 pfile_info->LastWriteTime = 0; /* BB fixme */
1256 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001257 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001258 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001260 pfile_info->AllocationSize =
1261 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1262 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001263 pfile_info->NumberOfLinks = cpu_to_le32(1);
1264 }
1265 }
1266
1267 cifs_buf_release(pSMB);
1268 if (rc == -EAGAIN)
1269 goto OldOpenRetry;
1270 return rc;
1271}
1272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273int
1274CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1275 const char *fileName, const int openDisposition,
1276 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001277 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001278 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279{
1280 int rc = -EACCES;
1281 OPEN_REQ *pSMB = NULL;
1282 OPEN_RSP *pSMBr = NULL;
1283 int bytes_returned;
1284 int name_len;
1285 __u16 count;
1286
1287openRetry:
1288 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1289 (void **) &pSMBr);
1290 if (rc)
1291 return rc;
1292
1293 pSMB->AndXCommand = 0xFF; /* none */
1294
1295 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1296 count = 1; /* account for one byte pad to word boundary */
1297 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001298 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001299 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 name_len++; /* trailing null */
1301 name_len *= 2;
1302 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001303 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 count = 0; /* no pad */
1305 name_len = strnlen(fileName, PATH_MAX);
1306 name_len++; /* trailing null */
1307 pSMB->NameLength = cpu_to_le16(name_len);
1308 strncpy(pSMB->fileName, fileName, name_len);
1309 }
1310 if (*pOplock & REQ_OPLOCK)
1311 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001312 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1315 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001316 /* set file as system file if special file such
1317 as fifo and server expecting SFU style and
1318 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001319 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001320 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1321 else
1322 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 /* XP does not handle ATTR_POSIX_SEMANTICS */
1324 /* but it helps speed up case sensitive checks for other
1325 servers such as Samba */
1326 if (tcon->ses->capabilities & CAP_UNIX)
1327 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1328
1329 /* if ((omode & S_IWUGO) == 0)
1330 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1331 /* Above line causes problems due to vfs splitting create into two
1332 pieces - need to set mode after file created not while it is
1333 being created */
1334 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1335 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001336 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001337 /* BB Expirement with various impersonation levels and verify */
1338 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 pSMB->SecurityFlags =
1340 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1341
1342 count += name_len;
1343 pSMB->hdr.smb_buf_length += count;
1344
1345 pSMB->ByteCount = cpu_to_le16(count);
1346 /* long_op set to 1 to allow for oplock break timeouts */
1347 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1348 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001349 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 if (rc) {
1351 cFYI(1, ("Error in Open = %d", rc));
1352 } else {
Steve French09d1db52005-04-28 22:41:08 -07001353 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1355 /* Let caller know file was created so we can set the mode. */
1356 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001357 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001358 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001359 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001360 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 36 /* CreationTime to Attributes */);
1362 /* the file_info buf is endian converted by caller */
1363 pfile_info->AllocationSize = pSMBr->AllocationSize;
1364 pfile_info->EndOfFile = pSMBr->EndOfFile;
1365 pfile_info->NumberOfLinks = cpu_to_le32(1);
1366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001368
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 cifs_buf_release(pSMB);
1370 if (rc == -EAGAIN)
1371 goto openRetry;
1372 return rc;
1373}
1374
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375int
Steve French50c2f752007-07-13 00:33:32 +00001376CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1377 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1378 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379{
1380 int rc = -EACCES;
1381 READ_REQ *pSMB = NULL;
1382 READ_RSP *pSMBr = NULL;
1383 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001384 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001385 int resp_buf_type = 0;
1386 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
Steve French790fe572007-07-07 19:25:05 +00001388 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1389 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001390 wct = 12;
1391 else
1392 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001395 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 if (rc)
1397 return rc;
1398
1399 /* tcon and ses pointer are checked in smb_init */
1400 if (tcon->ses->server == NULL)
1401 return -ECONNABORTED;
1402
Steve Frenchec637e32005-12-12 20:53:18 -08001403 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 pSMB->Fid = netfid;
1405 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001406 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001407 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001408 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001409 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001410
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 pSMB->Remaining = 0;
1412 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1413 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001414 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001415 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1416 else {
1417 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001418 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001419 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001420 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001421 }
Steve Frenchec637e32005-12-12 20:53:18 -08001422
1423 iov[0].iov_base = (char *)pSMB;
1424 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve French50c2f752007-07-13 00:33:32 +00001425 rc = SendReceive2(xid, tcon->ses, iov,
Steve Frenchec637e32005-12-12 20:53:18 -08001426 1 /* num iovecs */,
Steve French50c2f752007-07-13 00:33:32 +00001427 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001428 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001429 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 if (rc) {
1431 cERROR(1, ("Send error in read = %d", rc));
1432 } else {
1433 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1434 data_length = data_length << 16;
1435 data_length += le16_to_cpu(pSMBr->DataLength);
1436 *nbytes = data_length;
1437
1438 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001439 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001441 cFYI(1, ("bad length %d for count %d",
1442 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 rc = -EIO;
1444 *nbytes = 0;
1445 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001446 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001447 le16_to_cpu(pSMBr->DataOffset);
1448/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001449 cERROR(1,("Faulting on read rc = %d",rc));
1450 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001451 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001452 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001453 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 }
1455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
Steve French4b8f9302006-02-26 16:41:18 +00001457/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001458 if (*buf) {
1459 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001460 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001461 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001462 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001463 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001464 /* return buffer to caller to free */
1465 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001466 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001467 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001468 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001469 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001470 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001471
1472 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 since file handle passed in no longer valid */
1474 return rc;
1475}
1476
Steve Frenchec637e32005-12-12 20:53:18 -08001477
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478int
1479CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1480 const int netfid, const unsigned int count,
1481 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001482 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
1484 int rc = -EACCES;
1485 WRITE_REQ *pSMB = NULL;
1486 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001487 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 __u32 bytes_sent;
1489 __u16 byte_count;
1490
1491 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001492 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001493 return -ECONNABORTED;
1494
Steve French790fe572007-07-07 19:25:05 +00001495 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001496 wct = 14;
1497 else
1498 wct = 12;
1499
1500 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 (void **) &pSMBr);
1502 if (rc)
1503 return rc;
1504 /* tcon and ses pointer are checked in smb_init */
1505 if (tcon->ses->server == NULL)
1506 return -ECONNABORTED;
1507
1508 pSMB->AndXCommand = 0xFF; /* none */
1509 pSMB->Fid = netfid;
1510 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001511 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001512 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001513 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001514 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001515
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 pSMB->Reserved = 0xFFFFFFFF;
1517 pSMB->WriteMode = 0;
1518 pSMB->Remaining = 0;
1519
Steve French50c2f752007-07-13 00:33:32 +00001520 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 can send more if LARGE_WRITE_X capability returned by the server and if
1522 our buffer is big enough or if we convert to iovecs on socket writes
1523 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001524 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1526 } else {
1527 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1528 & ~0xFF;
1529 }
1530
1531 if (bytes_sent > count)
1532 bytes_sent = count;
1533 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001534 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001535 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001536 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001537 else if (ubuf) {
1538 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 cifs_buf_release(pSMB);
1540 return -EFAULT;
1541 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001542 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 /* No buffer */
1544 cifs_buf_release(pSMB);
1545 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001546 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001547 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001548 byte_count = bytes_sent + 1; /* pad */
1549 else /* wct == 12 */ {
1550 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1553 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001554 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001555
Steve French790fe572007-07-07 19:25:05 +00001556 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001557 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001558 else { /* old style write has byte count 4 bytes earlier
1559 so 4 bytes pad */
1560 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001561 (struct smb_com_writex_req *)pSMB;
1562 pSMBW->ByteCount = cpu_to_le16(byte_count);
1563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
1565 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1566 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001567 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 if (rc) {
1569 cFYI(1, ("Send error in write = %d", rc));
1570 *nbytes = 0;
1571 } else {
1572 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1573 *nbytes = (*nbytes) << 16;
1574 *nbytes += le16_to_cpu(pSMBr->Count);
1575 }
1576
1577 cifs_buf_release(pSMB);
1578
Steve French50c2f752007-07-13 00:33:32 +00001579 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 since file handle passed in no longer valid */
1581
1582 return rc;
1583}
1584
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001585int
1586CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001588 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1589 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590{
1591 int rc = -EACCES;
1592 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001593 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001594 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001595 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
Steve French790fe572007-07-07 19:25:05 +00001597 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001598
Steve French790fe572007-07-07 19:25:05 +00001599 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001600 wct = 14;
1601 else
1602 wct = 12;
1603 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 if (rc)
1605 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 /* tcon and ses pointer are checked in smb_init */
1607 if (tcon->ses->server == NULL)
1608 return -ECONNABORTED;
1609
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001610 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 pSMB->Fid = netfid;
1612 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001613 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001614 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001615 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001616 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 pSMB->Reserved = 0xFFFFFFFF;
1618 pSMB->WriteMode = 0;
1619 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001620
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001622 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
Steve French3e844692005-10-03 13:37:24 -07001624 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1625 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001626 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001627 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001628 pSMB->hdr.smb_buf_length += count+1;
1629 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001630 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1631 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001632 pSMB->ByteCount = cpu_to_le16(count + 1);
1633 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001634 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001635 (struct smb_com_writex_req *)pSMB;
1636 pSMBW->ByteCount = cpu_to_le16(count + 5);
1637 }
Steve French3e844692005-10-03 13:37:24 -07001638 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001639 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001640 iov[0].iov_len = smb_hdr_len + 4;
1641 else /* wct == 12 pad bigger by four bytes */
1642 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001643
Steve French3e844692005-10-03 13:37:24 -07001644
Steve Frenchec637e32005-12-12 20:53:18 -08001645 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001646 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001647 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001649 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001651 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001652 /* presumably this can not happen, but best to be safe */
1653 rc = -EIO;
1654 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001655 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001656 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001657 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1658 *nbytes = (*nbytes) << 16;
1659 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
Steve French4b8f9302006-02-26 16:41:18 +00001662/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001663 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001664 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001665 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001666 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
Steve French50c2f752007-07-13 00:33:32 +00001668 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 since file handle passed in no longer valid */
1670
1671 return rc;
1672}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001673
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675int
1676CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1677 const __u16 smb_file_id, const __u64 len,
1678 const __u64 offset, const __u32 numUnlock,
1679 const __u32 numLock, const __u8 lockType, const int waitFlag)
1680{
1681 int rc = 0;
1682 LOCK_REQ *pSMB = NULL;
1683 LOCK_RSP *pSMBr = NULL;
1684 int bytes_returned;
1685 int timeout = 0;
1686 __u16 count;
1687
Steve French50c2f752007-07-13 00:33:32 +00001688 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001689 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1690
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 if (rc)
1692 return rc;
1693
Steve French46810cb2005-04-28 22:41:09 -07001694 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1695
Steve French790fe572007-07-07 19:25:05 +00001696 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 timeout = -1; /* no response expected */
1698 pSMB->Timeout = 0;
1699 } else if (waitFlag == TRUE) {
1700 timeout = 3; /* blocking operation, no timeout */
1701 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1702 } else {
1703 pSMB->Timeout = 0;
1704 }
1705
1706 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1707 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1708 pSMB->LockType = lockType;
1709 pSMB->AndXCommand = 0xFF; /* none */
1710 pSMB->Fid = smb_file_id; /* netfid stays le */
1711
Steve French790fe572007-07-07 19:25:05 +00001712 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1714 /* BB where to store pid high? */
1715 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1716 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1717 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1718 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1719 count = sizeof(LOCKING_ANDX_RANGE);
1720 } else {
1721 /* oplock break */
1722 count = 0;
1723 }
1724 pSMB->hdr.smb_buf_length += count;
1725 pSMB->ByteCount = cpu_to_le16(count);
1726
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001727 if (waitFlag) {
1728 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1729 (struct smb_hdr *) pSMBr, &bytes_returned);
1730 } else {
1731 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001733 }
Steve Frencha4544342005-08-24 13:59:35 -07001734 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 if (rc) {
1736 cFYI(1, ("Send error in Lock = %d", rc));
1737 }
Steve French46810cb2005-04-28 22:41:09 -07001738 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
Steve French50c2f752007-07-13 00:33:32 +00001740 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 since file handle passed in no longer valid */
1742 return rc;
1743}
1744
1745int
Steve French08547b02006-02-28 22:39:25 +00001746CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1747 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001748 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001749 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001750{
1751 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1752 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001753 struct cifs_posix_lock *parm_data;
1754 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001755 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001756 int bytes_returned = 0;
1757 __u16 params, param_offset, offset, byte_count, count;
1758
1759 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001760
Steve French790fe572007-07-07 19:25:05 +00001761 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001762 return EINVAL;
1763
Steve French08547b02006-02-28 22:39:25 +00001764 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1765
1766 if (rc)
1767 return rc;
1768
1769 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1770
Steve French50c2f752007-07-13 00:33:32 +00001771 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001772 pSMB->MaxSetupCount = 0;
1773 pSMB->Reserved = 0;
1774 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001775 pSMB->Reserved2 = 0;
1776 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1777 offset = param_offset + params;
1778
Steve French08547b02006-02-28 22:39:25 +00001779 count = sizeof(struct cifs_posix_lock);
1780 pSMB->MaxParameterCount = cpu_to_le16(2);
1781 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1782 pSMB->SetupCount = 1;
1783 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001784 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001785 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1786 else
1787 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1788 byte_count = 3 /* pad */ + params + count;
1789 pSMB->DataCount = cpu_to_le16(count);
1790 pSMB->ParameterCount = cpu_to_le16(params);
1791 pSMB->TotalDataCount = pSMB->DataCount;
1792 pSMB->TotalParameterCount = pSMB->ParameterCount;
1793 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001794 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001795 (((char *) &pSMB->hdr.Protocol) + offset);
1796
1797 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001798 if (waitFlag) {
Steve French3a5ff612006-07-14 22:37:11 +00001799 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001800 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001801 pSMB->Timeout = cpu_to_le32(-1);
1802 } else
1803 pSMB->Timeout = 0;
1804
Steve French08547b02006-02-28 22:39:25 +00001805 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001806 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001807 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001808
1809 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001810 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001811 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1812 pSMB->Reserved4 = 0;
1813 pSMB->hdr.smb_buf_length += byte_count;
1814 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001815 if (waitFlag) {
1816 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1817 (struct smb_hdr *) pSMBr, &bytes_returned);
1818 } else {
1819 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001820 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001821 }
1822
Steve French08547b02006-02-28 22:39:25 +00001823 if (rc) {
1824 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001825 } else if (get_flag) {
1826 /* lock structure can be returned on get */
1827 __u16 data_offset;
1828 __u16 data_count;
1829 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001830
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001831 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1832 rc = -EIO; /* bad smb */
1833 goto plk_err_exit;
1834 }
Steve French790fe572007-07-07 19:25:05 +00001835 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001836 rc = -EINVAL;
1837 goto plk_err_exit;
1838 }
1839 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1840 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001841 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001842 rc = -EIO;
1843 goto plk_err_exit;
1844 }
1845 parm_data = (struct cifs_posix_lock *)
1846 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001847 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001848 pLockData->fl_type = F_UNLCK;
1849 }
Steve French50c2f752007-07-13 00:33:32 +00001850
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001851plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001852 if (pSMB)
1853 cifs_small_buf_release(pSMB);
1854
1855 /* Note: On -EAGAIN error only caller can retry on handle based calls
1856 since file handle passed in no longer valid */
1857
1858 return rc;
1859}
1860
1861
1862int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1864{
1865 int rc = 0;
1866 CLOSE_REQ *pSMB = NULL;
1867 CLOSE_RSP *pSMBr = NULL;
1868 int bytes_returned;
1869 cFYI(1, ("In CIFSSMBClose"));
1870
1871/* do not retry on dead session on close */
1872 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001873 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 return 0;
1875 if (rc)
1876 return rc;
1877
1878 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1879
1880 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001881 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 pSMB->ByteCount = 0;
1883 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1884 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001885 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001887 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 /* EINTR is expected when user ctl-c to kill app */
1889 cERROR(1, ("Send error in Close = %d", rc));
1890 }
1891 }
1892
1893 cifs_small_buf_release(pSMB);
1894
1895 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001896 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 rc = 0;
1898
1899 return rc;
1900}
1901
1902int
1903CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1904 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001905 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906{
1907 int rc = 0;
1908 RENAME_REQ *pSMB = NULL;
1909 RENAME_RSP *pSMBr = NULL;
1910 int bytes_returned;
1911 int name_len, name_len2;
1912 __u16 count;
1913
1914 cFYI(1, ("In CIFSSMBRename"));
1915renameRetry:
1916 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1917 (void **) &pSMBr);
1918 if (rc)
1919 return rc;
1920
1921 pSMB->BufferFormat = 0x04;
1922 pSMB->SearchAttributes =
1923 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1924 ATTR_DIRECTORY);
1925
1926 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1927 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001928 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001929 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 name_len++; /* trailing null */
1931 name_len *= 2;
1932 pSMB->OldFileName[name_len] = 0x04; /* pad */
1933 /* protocol requires ASCII signature byte on Unicode string */
1934 pSMB->OldFileName[name_len + 1] = 0x00;
1935 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001936 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001937 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1939 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001940 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 name_len = strnlen(fromName, PATH_MAX);
1942 name_len++; /* trailing null */
1943 strncpy(pSMB->OldFileName, fromName, name_len);
1944 name_len2 = strnlen(toName, PATH_MAX);
1945 name_len2++; /* trailing null */
1946 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1947 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1948 name_len2++; /* trailing null */
1949 name_len2++; /* signature byte */
1950 }
1951
1952 count = 1 /* 1st signature byte */ + name_len + name_len2;
1953 pSMB->hdr.smb_buf_length += count;
1954 pSMB->ByteCount = cpu_to_le16(count);
1955
1956 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1957 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001958 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 if (rc) {
1960 cFYI(1, ("Send error in rename = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +00001961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 cifs_buf_release(pSMB);
1964
1965 if (rc == -EAGAIN)
1966 goto renameRetry;
1967
1968 return rc;
1969}
1970
Steve French50c2f752007-07-13 00:33:32 +00001971int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1972 int netfid, char *target_name,
1973 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974{
1975 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1976 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001977 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 char *data_offset;
1979 char dummy_string[30];
1980 int rc = 0;
1981 int bytes_returned = 0;
1982 int len_of_str;
1983 __u16 params, param_offset, offset, count, byte_count;
1984
1985 cFYI(1, ("Rename to File by handle"));
1986 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1987 (void **) &pSMBr);
1988 if (rc)
1989 return rc;
1990
1991 params = 6;
1992 pSMB->MaxSetupCount = 0;
1993 pSMB->Reserved = 0;
1994 pSMB->Flags = 0;
1995 pSMB->Timeout = 0;
1996 pSMB->Reserved2 = 0;
1997 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1998 offset = param_offset + params;
1999
2000 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2001 rename_info = (struct set_file_rename *) data_offset;
2002 pSMB->MaxParameterCount = cpu_to_le16(2);
2003 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2004 pSMB->SetupCount = 1;
2005 pSMB->Reserved3 = 0;
2006 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2007 byte_count = 3 /* pad */ + params;
2008 pSMB->ParameterCount = cpu_to_le16(params);
2009 pSMB->TotalParameterCount = pSMB->ParameterCount;
2010 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2011 pSMB->DataOffset = cpu_to_le16(offset);
2012 /* construct random name ".cifs_tmp<inodenum><mid>" */
2013 rename_info->overwrite = cpu_to_le32(1);
2014 rename_info->root_fid = 0;
2015 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002016 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002017 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2018 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002019 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002021 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002022 target_name, PATH_MAX, nls_codepage,
2023 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 }
2025 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2026 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2027 byte_count += count;
2028 pSMB->DataCount = cpu_to_le16(count);
2029 pSMB->TotalDataCount = pSMB->DataCount;
2030 pSMB->Fid = netfid;
2031 pSMB->InformationLevel =
2032 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2033 pSMB->Reserved4 = 0;
2034 pSMB->hdr.smb_buf_length += byte_count;
2035 pSMB->ByteCount = cpu_to_le16(byte_count);
2036 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002037 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002038 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002040 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 }
Steve Frencha5a2b482005-08-20 21:42:53 -07002042
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 cifs_buf_release(pSMB);
2044
2045 /* Note: On -EAGAIN error only caller can retry on handle based calls
2046 since file handle passed in no longer valid */
2047
2048 return rc;
2049}
2050
2051int
Steve French50c2f752007-07-13 00:33:32 +00002052CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2053 const __u16 target_tid, const char *toName, const int flags,
2054 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055{
2056 int rc = 0;
2057 COPY_REQ *pSMB = NULL;
2058 COPY_RSP *pSMBr = NULL;
2059 int bytes_returned;
2060 int name_len, name_len2;
2061 __u16 count;
2062
2063 cFYI(1, ("In CIFSSMBCopy"));
2064copyRetry:
2065 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2066 (void **) &pSMBr);
2067 if (rc)
2068 return rc;
2069
2070 pSMB->BufferFormat = 0x04;
2071 pSMB->Tid2 = target_tid;
2072
2073 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2074
2075 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002076 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002077 fromName, PATH_MAX, nls_codepage,
2078 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 name_len++; /* trailing null */
2080 name_len *= 2;
2081 pSMB->OldFileName[name_len] = 0x04; /* pad */
2082 /* protocol requires ASCII signature byte on Unicode string */
2083 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002084 name_len2 =
2085 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002086 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2088 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002089 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 name_len = strnlen(fromName, PATH_MAX);
2091 name_len++; /* trailing null */
2092 strncpy(pSMB->OldFileName, fromName, name_len);
2093 name_len2 = strnlen(toName, PATH_MAX);
2094 name_len2++; /* trailing null */
2095 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2096 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2097 name_len2++; /* trailing null */
2098 name_len2++; /* signature byte */
2099 }
2100
2101 count = 1 /* 1st signature byte */ + name_len + name_len2;
2102 pSMB->hdr.smb_buf_length += count;
2103 pSMB->ByteCount = cpu_to_le16(count);
2104
2105 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2106 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2107 if (rc) {
2108 cFYI(1, ("Send error in copy = %d with %d files copied",
2109 rc, le16_to_cpu(pSMBr->CopyCount)));
2110 }
2111 if (pSMB)
2112 cifs_buf_release(pSMB);
2113
2114 if (rc == -EAGAIN)
2115 goto copyRetry;
2116
2117 return rc;
2118}
2119
2120int
2121CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2122 const char *fromName, const char *toName,
2123 const struct nls_table *nls_codepage)
2124{
2125 TRANSACTION2_SPI_REQ *pSMB = NULL;
2126 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2127 char *data_offset;
2128 int name_len;
2129 int name_len_target;
2130 int rc = 0;
2131 int bytes_returned = 0;
2132 __u16 params, param_offset, offset, byte_count;
2133
2134 cFYI(1, ("In Symlink Unix style"));
2135createSymLinkRetry:
2136 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2137 (void **) &pSMBr);
2138 if (rc)
2139 return rc;
2140
2141 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2142 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002143 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 /* find define for this maxpathcomponent */
2145 , nls_codepage);
2146 name_len++; /* trailing null */
2147 name_len *= 2;
2148
Steve French50c2f752007-07-13 00:33:32 +00002149 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 name_len = strnlen(fromName, PATH_MAX);
2151 name_len++; /* trailing null */
2152 strncpy(pSMB->FileName, fromName, name_len);
2153 }
2154 params = 6 + name_len;
2155 pSMB->MaxSetupCount = 0;
2156 pSMB->Reserved = 0;
2157 pSMB->Flags = 0;
2158 pSMB->Timeout = 0;
2159 pSMB->Reserved2 = 0;
2160 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002161 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 offset = param_offset + params;
2163
2164 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2165 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2166 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002167 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 /* find define for this maxpathcomponent */
2169 , nls_codepage);
2170 name_len_target++; /* trailing null */
2171 name_len_target *= 2;
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_target = strnlen(toName, PATH_MAX);
2174 name_len_target++; /* trailing null */
2175 strncpy(data_offset, toName, name_len_target);
2176 }
2177
2178 pSMB->MaxParameterCount = cpu_to_le16(2);
2179 /* BB find exact max on data count below from sess */
2180 pSMB->MaxDataCount = cpu_to_le16(1000);
2181 pSMB->SetupCount = 1;
2182 pSMB->Reserved3 = 0;
2183 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2184 byte_count = 3 /* pad */ + params + name_len_target;
2185 pSMB->DataCount = cpu_to_le16(name_len_target);
2186 pSMB->ParameterCount = cpu_to_le16(params);
2187 pSMB->TotalDataCount = pSMB->DataCount;
2188 pSMB->TotalParameterCount = pSMB->ParameterCount;
2189 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2190 pSMB->DataOffset = cpu_to_le16(offset);
2191 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2192 pSMB->Reserved4 = 0;
2193 pSMB->hdr.smb_buf_length += byte_count;
2194 pSMB->ByteCount = cpu_to_le16(byte_count);
2195 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2196 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002197 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 if (rc) {
Steve French2d785a52007-07-15 01:48:57 +00002199 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 }
2201
2202 if (pSMB)
2203 cifs_buf_release(pSMB);
2204
2205 if (rc == -EAGAIN)
2206 goto createSymLinkRetry;
2207
2208 return rc;
2209}
2210
2211int
2212CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2213 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002214 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215{
2216 TRANSACTION2_SPI_REQ *pSMB = NULL;
2217 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2218 char *data_offset;
2219 int name_len;
2220 int name_len_target;
2221 int rc = 0;
2222 int bytes_returned = 0;
2223 __u16 params, param_offset, offset, byte_count;
2224
2225 cFYI(1, ("In Create Hard link Unix style"));
2226createHardLinkRetry:
2227 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2228 (void **) &pSMBr);
2229 if (rc)
2230 return rc;
2231
2232 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002233 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002234 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 name_len++; /* trailing null */
2236 name_len *= 2;
2237
Steve French50c2f752007-07-13 00:33:32 +00002238 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 name_len = strnlen(toName, PATH_MAX);
2240 name_len++; /* trailing null */
2241 strncpy(pSMB->FileName, toName, name_len);
2242 }
2243 params = 6 + name_len;
2244 pSMB->MaxSetupCount = 0;
2245 pSMB->Reserved = 0;
2246 pSMB->Flags = 0;
2247 pSMB->Timeout = 0;
2248 pSMB->Reserved2 = 0;
2249 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002250 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 offset = param_offset + params;
2252
2253 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2254 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2255 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002256 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002257 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 name_len_target++; /* trailing null */
2259 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002260 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 name_len_target = strnlen(fromName, PATH_MAX);
2262 name_len_target++; /* trailing null */
2263 strncpy(data_offset, fromName, name_len_target);
2264 }
2265
2266 pSMB->MaxParameterCount = cpu_to_le16(2);
2267 /* BB find exact max on data count below from sess*/
2268 pSMB->MaxDataCount = cpu_to_le16(1000);
2269 pSMB->SetupCount = 1;
2270 pSMB->Reserved3 = 0;
2271 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2272 byte_count = 3 /* pad */ + params + name_len_target;
2273 pSMB->ParameterCount = cpu_to_le16(params);
2274 pSMB->TotalParameterCount = pSMB->ParameterCount;
2275 pSMB->DataCount = cpu_to_le16(name_len_target);
2276 pSMB->TotalDataCount = pSMB->DataCount;
2277 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2278 pSMB->DataOffset = cpu_to_le16(offset);
2279 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2280 pSMB->Reserved4 = 0;
2281 pSMB->hdr.smb_buf_length += byte_count;
2282 pSMB->ByteCount = cpu_to_le16(byte_count);
2283 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2284 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002285 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 if (rc) {
2287 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2288 }
2289
2290 cifs_buf_release(pSMB);
2291 if (rc == -EAGAIN)
2292 goto createHardLinkRetry;
2293
2294 return rc;
2295}
2296
2297int
2298CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2299 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002300 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301{
2302 int rc = 0;
2303 NT_RENAME_REQ *pSMB = NULL;
2304 RENAME_RSP *pSMBr = NULL;
2305 int bytes_returned;
2306 int name_len, name_len2;
2307 __u16 count;
2308
2309 cFYI(1, ("In CIFSCreateHardLink"));
2310winCreateHardLinkRetry:
2311
2312 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2313 (void **) &pSMBr);
2314 if (rc)
2315 return rc;
2316
2317 pSMB->SearchAttributes =
2318 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2319 ATTR_DIRECTORY);
2320 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2321 pSMB->ClusterCount = 0;
2322
2323 pSMB->BufferFormat = 0x04;
2324
2325 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2326 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002327 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002328 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 name_len++; /* trailing null */
2330 name_len *= 2;
2331 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002332 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002334 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002335 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2337 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002338 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 name_len = strnlen(fromName, PATH_MAX);
2340 name_len++; /* trailing null */
2341 strncpy(pSMB->OldFileName, fromName, name_len);
2342 name_len2 = strnlen(toName, PATH_MAX);
2343 name_len2++; /* trailing null */
2344 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2345 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2346 name_len2++; /* trailing null */
2347 name_len2++; /* signature byte */
2348 }
2349
2350 count = 1 /* string type byte */ + name_len + name_len2;
2351 pSMB->hdr.smb_buf_length += count;
2352 pSMB->ByteCount = cpu_to_le16(count);
2353
2354 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2355 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002356 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 if (rc) {
2358 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2359 }
2360 cifs_buf_release(pSMB);
2361 if (rc == -EAGAIN)
2362 goto winCreateHardLinkRetry;
2363
2364 return rc;
2365}
2366
2367int
2368CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2369 const unsigned char *searchName,
2370 char *symlinkinfo, const int buflen,
2371 const struct nls_table *nls_codepage)
2372{
2373/* SMB_QUERY_FILE_UNIX_LINK */
2374 TRANSACTION2_QPI_REQ *pSMB = NULL;
2375 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2376 int rc = 0;
2377 int bytes_returned;
2378 int name_len;
2379 __u16 params, byte_count;
2380
2381 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2382
2383querySymLinkRetry:
2384 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2385 (void **) &pSMBr);
2386 if (rc)
2387 return rc;
2388
2389 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2390 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002391 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2392 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 name_len++; /* trailing null */
2394 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002395 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 name_len = strnlen(searchName, PATH_MAX);
2397 name_len++; /* trailing null */
2398 strncpy(pSMB->FileName, searchName, name_len);
2399 }
2400
2401 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2402 pSMB->TotalDataCount = 0;
2403 pSMB->MaxParameterCount = cpu_to_le16(2);
2404 /* BB find exact max data count below from sess structure BB */
2405 pSMB->MaxDataCount = cpu_to_le16(4000);
2406 pSMB->MaxSetupCount = 0;
2407 pSMB->Reserved = 0;
2408 pSMB->Flags = 0;
2409 pSMB->Timeout = 0;
2410 pSMB->Reserved2 = 0;
2411 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002412 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 pSMB->DataCount = 0;
2414 pSMB->DataOffset = 0;
2415 pSMB->SetupCount = 1;
2416 pSMB->Reserved3 = 0;
2417 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2418 byte_count = params + 1 /* pad */ ;
2419 pSMB->TotalParameterCount = cpu_to_le16(params);
2420 pSMB->ParameterCount = pSMB->TotalParameterCount;
2421 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2422 pSMB->Reserved4 = 0;
2423 pSMB->hdr.smb_buf_length += byte_count;
2424 pSMB->ByteCount = cpu_to_le16(byte_count);
2425
2426 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2427 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2428 if (rc) {
2429 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2430 } else {
2431 /* decode response */
2432
2433 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2434 if (rc || (pSMBr->ByteCount < 2))
2435 /* BB also check enough total bytes returned */
2436 rc = -EIO; /* bad smb */
2437 else {
2438 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2439 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2440
2441 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2442 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002443 &pSMBr->hdr.Protocol + data_offset),
2444 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002445 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002447 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2448 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 name_len, nls_codepage);
2450 } else {
2451 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002452 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 data_offset,
2454 min_t(const int, buflen, count));
2455 }
2456 symlinkinfo[buflen] = 0;
2457 /* just in case so calling code does not go off the end of buffer */
2458 }
2459 }
2460 cifs_buf_release(pSMB);
2461 if (rc == -EAGAIN)
2462 goto querySymLinkRetry;
2463 return rc;
2464}
2465
Steve French0a4b92c2006-01-12 15:44:21 -08002466/* Initialize NT TRANSACT SMB into small smb request buffer.
2467 This assumes that all NT TRANSACTS that we init here have
2468 total parm and data under about 400 bytes (to fit in small cifs
2469 buffer size), which is the case so far, it easily fits. NB:
2470 Setup words themselves and ByteCount
2471 MaxSetupCount (size of returned setup area) and
2472 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002473static int
Steve French0a4b92c2006-01-12 15:44:21 -08002474smb_init_ntransact(const __u16 sub_command, const int setup_count,
2475 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002476 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002477{
2478 int rc;
2479 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002480 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002481
2482 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2483 (void **)&pSMB);
2484 if (rc)
2485 return rc;
2486 *ret_buf = (void *)pSMB;
2487 pSMB->Reserved = 0;
2488 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2489 pSMB->TotalDataCount = 0;
2490 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2491 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2492 pSMB->ParameterCount = pSMB->TotalParameterCount;
2493 pSMB->DataCount = pSMB->TotalDataCount;
2494 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2495 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2496 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2497 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2498 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2499 pSMB->SubCommand = cpu_to_le16(sub_command);
2500 return 0;
2501}
2502
2503static int
Steve French50c2f752007-07-13 00:33:32 +00002504validate_ntransact(char *buf, char **ppparm, char **ppdata,
2505 int *pdatalen, int *pparmlen)
Steve French0a4b92c2006-01-12 15:44:21 -08002506{
Steve French50c2f752007-07-13 00:33:32 +00002507 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002508 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002509 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002510
Steve French790fe572007-07-07 19:25:05 +00002511 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002512 return -EINVAL;
2513
2514 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2515
2516 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002517 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002518 (char *)&pSMBr->ByteCount;
2519
Steve French0a4b92c2006-01-12 15:44:21 -08002520 data_offset = le32_to_cpu(pSMBr->DataOffset);
2521 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002522 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002523 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2524
2525 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2526 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2527
2528 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002529 if (*ppparm > end_of_smb) {
2530 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002531 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002532 } else if (parm_count + *ppparm > end_of_smb) {
2533 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002534 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002535 } else if (*ppdata > end_of_smb) {
2536 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002537 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002538 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002539 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002540 *ppdata, data_count, (data_count + *ppdata),
2541 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002542 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002543 } else if (parm_count + data_count > pSMBr->ByteCount) {
2544 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002545 return -EINVAL;
2546 }
2547 return 0;
2548}
2549
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550int
2551CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2552 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002553 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 const struct nls_table *nls_codepage)
2555{
2556 int rc = 0;
2557 int bytes_returned;
2558 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002559 struct smb_com_transaction_ioctl_req *pSMB;
2560 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561
2562 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2563 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2564 (void **) &pSMBr);
2565 if (rc)
2566 return rc;
2567
2568 pSMB->TotalParameterCount = 0 ;
2569 pSMB->TotalDataCount = 0;
2570 pSMB->MaxParameterCount = cpu_to_le32(2);
2571 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002572 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2573 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 pSMB->MaxSetupCount = 4;
2575 pSMB->Reserved = 0;
2576 pSMB->ParameterOffset = 0;
2577 pSMB->DataCount = 0;
2578 pSMB->DataOffset = 0;
2579 pSMB->SetupCount = 4;
2580 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2581 pSMB->ParameterCount = pSMB->TotalParameterCount;
2582 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2583 pSMB->IsFsctl = 1; /* FSCTL */
2584 pSMB->IsRootFlag = 0;
2585 pSMB->Fid = fid; /* file handle always le */
2586 pSMB->ByteCount = 0;
2587
2588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2589 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2590 if (rc) {
2591 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2592 } else { /* decode response */
2593 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2594 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2595 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2596 /* BB also check enough total bytes returned */
2597 rc = -EIO; /* bad smb */
2598 else {
Steve French790fe572007-07-07 19:25:05 +00002599 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002600 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002601 pSMBr->ByteCount +
2602 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603
Steve French50c2f752007-07-13 00:33:32 +00002604 struct reparse_data *reparse_buf =
2605 (struct reparse_data *)
2606 ((char *)&pSMBr->hdr.Protocol
2607 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002608 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 rc = -EIO;
2610 goto qreparse_out;
2611 }
Steve French790fe572007-07-07 19:25:05 +00002612 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 reparse_buf->TargetNameOffset +
2614 reparse_buf->TargetNameLen) >
2615 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002616 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 rc = -EIO;
2618 goto qreparse_out;
2619 }
Steve French50c2f752007-07-13 00:33:32 +00002620
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2622 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002623 (reparse_buf->LinkNamesBuf +
2624 reparse_buf->TargetNameOffset),
2625 min(buflen/2,
2626 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002628 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 reparse_buf->TargetNameOffset),
2630 name_len, nls_codepage);
2631 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002632 strncpy(symlinkinfo,
2633 reparse_buf->LinkNamesBuf +
2634 reparse_buf->TargetNameOffset,
2635 min_t(const int, buflen,
2636 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 }
2638 } else {
2639 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002640 cFYI(1, ("Invalid return data count on "
2641 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 }
2643 symlinkinfo[buflen] = 0; /* just in case so the caller
2644 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002645 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 }
2647 }
2648qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002649 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650
2651 /* Note: On -EAGAIN error only caller can retry on handle based calls
2652 since file handle passed in no longer valid */
2653
2654 return rc;
2655}
2656
2657#ifdef CONFIG_CIFS_POSIX
2658
2659/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002660static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2661 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662{
2663 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002664 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2665 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2666 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2668
2669 return;
2670}
2671
2672/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002673static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2674 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675{
2676 int size = 0;
2677 int i;
2678 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002679 struct cifs_posix_ace *pACE;
2680 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2681 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682
2683 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2684 return -EOPNOTSUPP;
2685
Steve French790fe572007-07-07 19:25:05 +00002686 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 count = le16_to_cpu(cifs_acl->access_entry_count);
2688 pACE = &cifs_acl->ace_array[0];
2689 size = sizeof(struct cifs_posix_acl);
2690 size += sizeof(struct cifs_posix_ace) * count;
2691 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002692 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002693 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2694 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 return -EINVAL;
2696 }
Steve French790fe572007-07-07 19:25:05 +00002697 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 count = le16_to_cpu(cifs_acl->access_entry_count);
2699 size = sizeof(struct cifs_posix_acl);
2700 size += sizeof(struct cifs_posix_ace) * count;
2701/* skip past access ACEs to get to default ACEs */
2702 pACE = &cifs_acl->ace_array[count];
2703 count = le16_to_cpu(cifs_acl->default_entry_count);
2704 size += sizeof(struct cifs_posix_ace) * count;
2705 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002706 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 return -EINVAL;
2708 } else {
2709 /* illegal type */
2710 return -EINVAL;
2711 }
2712
2713 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002714 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002715 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002716 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 return -ERANGE;
2718 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002719 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002720 for (i = 0; i < count ; i++) {
2721 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2722 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 }
2724 }
2725 return size;
2726}
2727
Steve French50c2f752007-07-13 00:33:32 +00002728static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2729 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730{
2731 __u16 rc = 0; /* 0 = ACL converted ok */
2732
Steve Frenchff7feac2005-11-15 16:45:16 -08002733 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2734 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002736 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 /* Probably no need to le convert -1 on any arch but can not hurt */
2738 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002739 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002740 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002741 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 return rc;
2743}
2744
2745/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002746static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2747 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748{
2749 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002750 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2751 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 int count;
2753 int i;
2754
Steve French790fe572007-07-07 19:25:05 +00002755 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 return 0;
2757
2758 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002759 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002760 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002761 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002762 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002763 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002764 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 return 0;
2766 }
2767 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002768 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002769 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002770 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002771 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 else {
Steve French50c2f752007-07-13 00:33:32 +00002773 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 return 0;
2775 }
Steve French50c2f752007-07-13 00:33:32 +00002776 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2778 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002779 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 /* ACE not converted */
2781 break;
2782 }
2783 }
Steve French790fe572007-07-07 19:25:05 +00002784 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2786 rc += sizeof(struct cifs_posix_acl);
2787 /* BB add check to make sure ACL does not overflow SMB */
2788 }
2789 return rc;
2790}
2791
2792int
2793CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002794 const unsigned char *searchName,
2795 char *acl_inf, const int buflen, const int acl_type,
2796 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797{
2798/* SMB_QUERY_POSIX_ACL */
2799 TRANSACTION2_QPI_REQ *pSMB = NULL;
2800 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2801 int rc = 0;
2802 int bytes_returned;
2803 int name_len;
2804 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002805
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2807
2808queryAclRetry:
2809 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2810 (void **) &pSMBr);
2811 if (rc)
2812 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002813
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2815 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002816 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002817 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 name_len++; /* trailing null */
2819 name_len *= 2;
2820 pSMB->FileName[name_len] = 0;
2821 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002822 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 name_len = strnlen(searchName, PATH_MAX);
2824 name_len++; /* trailing null */
2825 strncpy(pSMB->FileName, searchName, name_len);
2826 }
2827
2828 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2829 pSMB->TotalDataCount = 0;
2830 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002831 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 pSMB->MaxDataCount = cpu_to_le16(4000);
2833 pSMB->MaxSetupCount = 0;
2834 pSMB->Reserved = 0;
2835 pSMB->Flags = 0;
2836 pSMB->Timeout = 0;
2837 pSMB->Reserved2 = 0;
2838 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002839 offsetof(struct smb_com_transaction2_qpi_req,
2840 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 pSMB->DataCount = 0;
2842 pSMB->DataOffset = 0;
2843 pSMB->SetupCount = 1;
2844 pSMB->Reserved3 = 0;
2845 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2846 byte_count = params + 1 /* pad */ ;
2847 pSMB->TotalParameterCount = cpu_to_le16(params);
2848 pSMB->ParameterCount = pSMB->TotalParameterCount;
2849 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2850 pSMB->Reserved4 = 0;
2851 pSMB->hdr.smb_buf_length += byte_count;
2852 pSMB->ByteCount = cpu_to_le16(byte_count);
2853
2854 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2855 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002856 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 if (rc) {
2858 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2859 } else {
2860 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002861
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2863 if (rc || (pSMBr->ByteCount < 2))
2864 /* BB also check enough total bytes returned */
2865 rc = -EIO; /* bad smb */
2866 else {
2867 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2868 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2869 rc = cifs_copy_posix_acl(acl_inf,
2870 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002871 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 }
2873 }
2874 cifs_buf_release(pSMB);
2875 if (rc == -EAGAIN)
2876 goto queryAclRetry;
2877 return rc;
2878}
2879
2880int
2881CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002882 const unsigned char *fileName,
2883 const char *local_acl, const int buflen,
2884 const int acl_type,
2885 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886{
2887 struct smb_com_transaction2_spi_req *pSMB = NULL;
2888 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2889 char *parm_data;
2890 int name_len;
2891 int rc = 0;
2892 int bytes_returned = 0;
2893 __u16 params, byte_count, data_count, param_offset, offset;
2894
2895 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2896setAclRetry:
2897 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002898 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 if (rc)
2900 return rc;
2901 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2902 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002903 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002904 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 name_len++; /* trailing null */
2906 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002907 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 name_len = strnlen(fileName, PATH_MAX);
2909 name_len++; /* trailing null */
2910 strncpy(pSMB->FileName, fileName, name_len);
2911 }
2912 params = 6 + name_len;
2913 pSMB->MaxParameterCount = cpu_to_le16(2);
2914 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2915 pSMB->MaxSetupCount = 0;
2916 pSMB->Reserved = 0;
2917 pSMB->Flags = 0;
2918 pSMB->Timeout = 0;
2919 pSMB->Reserved2 = 0;
2920 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002921 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 offset = param_offset + params;
2923 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2924 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2925
2926 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002927 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928
Steve French790fe572007-07-07 19:25:05 +00002929 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 rc = -EOPNOTSUPP;
2931 goto setACLerrorExit;
2932 }
2933 pSMB->DataOffset = cpu_to_le16(offset);
2934 pSMB->SetupCount = 1;
2935 pSMB->Reserved3 = 0;
2936 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2937 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2938 byte_count = 3 /* pad */ + params + data_count;
2939 pSMB->DataCount = cpu_to_le16(data_count);
2940 pSMB->TotalDataCount = pSMB->DataCount;
2941 pSMB->ParameterCount = cpu_to_le16(params);
2942 pSMB->TotalParameterCount = pSMB->ParameterCount;
2943 pSMB->Reserved4 = 0;
2944 pSMB->hdr.smb_buf_length += byte_count;
2945 pSMB->ByteCount = cpu_to_le16(byte_count);
2946 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002947 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 if (rc) {
2949 cFYI(1, ("Set POSIX ACL returned %d", rc));
2950 }
2951
2952setACLerrorExit:
2953 cifs_buf_release(pSMB);
2954 if (rc == -EAGAIN)
2955 goto setAclRetry;
2956 return rc;
2957}
2958
Steve Frenchf654bac2005-04-28 22:41:04 -07002959/* BB fix tabs in this function FIXME BB */
2960int
2961CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002962 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002963{
Steve French50c2f752007-07-13 00:33:32 +00002964 int rc = 0;
2965 struct smb_t2_qfi_req *pSMB = NULL;
2966 struct smb_t2_qfi_rsp *pSMBr = NULL;
2967 int bytes_returned;
2968 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002969
Steve French790fe572007-07-07 19:25:05 +00002970 cFYI(1, ("In GetExtAttr"));
2971 if (tcon == NULL)
2972 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002973
2974GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002975 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2976 (void **) &pSMBr);
2977 if (rc)
2978 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002979
Steve French790fe572007-07-07 19:25:05 +00002980 params = 2 /* level */ +2 /* fid */;
2981 pSMB->t2.TotalDataCount = 0;
2982 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2983 /* BB find exact max data count below from sess structure BB */
2984 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2985 pSMB->t2.MaxSetupCount = 0;
2986 pSMB->t2.Reserved = 0;
2987 pSMB->t2.Flags = 0;
2988 pSMB->t2.Timeout = 0;
2989 pSMB->t2.Reserved2 = 0;
2990 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2991 Fid) - 4);
2992 pSMB->t2.DataCount = 0;
2993 pSMB->t2.DataOffset = 0;
2994 pSMB->t2.SetupCount = 1;
2995 pSMB->t2.Reserved3 = 0;
2996 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2997 byte_count = params + 1 /* pad */ ;
2998 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2999 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3000 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3001 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003002 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003003 pSMB->hdr.smb_buf_length += byte_count;
3004 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003005
Steve French790fe572007-07-07 19:25:05 +00003006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3008 if (rc) {
3009 cFYI(1, ("error %d in GetExtAttr", rc));
3010 } else {
3011 /* decode response */
3012 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3013 if (rc || (pSMBr->ByteCount < 2))
3014 /* BB also check enough total bytes returned */
3015 /* If rc should we check for EOPNOSUPP and
3016 disable the srvino flag? or in caller? */
3017 rc = -EIO; /* bad smb */
3018 else {
3019 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3020 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3021 struct file_chattr_info *pfinfo;
3022 /* BB Do we need a cast or hash here ? */
3023 if (count != 16) {
3024 cFYI(1, ("Illegal size ret in GetExtAttr"));
3025 rc = -EIO;
3026 goto GetExtAttrOut;
3027 }
3028 pfinfo = (struct file_chattr_info *)
3029 (data_offset + (char *) &pSMBr->hdr.Protocol);
3030 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003031 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003032 }
3033 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003034GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003035 cifs_buf_release(pSMB);
3036 if (rc == -EAGAIN)
3037 goto GetExtAttrRetry;
3038 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003039}
3040
Steve Frenchf654bac2005-04-28 22:41:04 -07003041#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042
Steve Frencheeac8042006-01-13 21:34:58 -08003043
3044/* security id for everyone */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01003045static const struct cifs_sid sid_everyone =
Steve French2cd646a2006-09-28 19:43:08 +00003046 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08003047/* group users */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01003048static const struct cifs_sid sid_user =
Steve French2cd646a2006-09-28 19:43:08 +00003049 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08003050
Steve French442aa312007-09-24 20:25:46 +00003051static void parse_sid(struct cifs_sid * psid, char * end_of_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08003052{
Steve French442aa312007-09-24 20:25:46 +00003053 /* BB need to add parm so we can store the SID BB */
3054
3055 /* validate that we do not go past end of acl */
3056 if (end_of_acl < (char *)psid + sizeof(struct cifs_sid)) {
3057 cERROR(1, ("ACL to small to parse SID"));
3058 return;
3059 }
3060#ifdef CONFIG_CIFS_DEBUG2
3061 cFYI(1, ("revision %d num_auth %d First subauth 0x%x",
3062 psid->revision, psid->num_auth, psid->sub_auth[0]));
3063
3064 /* BB add length check to make sure that we do not have huge num auths
3065 and therefore go off the end */
3066 cFYI(1, ("RID 0x%x", le32_to_cpu(psid->sub_auth[psid->num_auth])));
3067#endif
3068 return;
3069}
3070
3071/* Convert CIFS ACL to POSIX form */
3072static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len)
3073{
3074 int i;
3075 int num_aces = 0;
3076 int acl_size;
3077 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
3078 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
3079 struct cifs_ntace **ppntace;
3080 struct cifs_ace **ppace;
3081 char *acl_base;
3082 char *end_of_acl = ((char *)pntsd) + acl_len;
3083
3084 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
3085 cpu_to_le32(pntsd->osidoffset));
3086 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
3087 cpu_to_le32(pntsd->gsidoffset));
3088 dacl_ptr = (struct cifs_acl *)((char *)pntsd +
3089 cpu_to_le32(pntsd->dacloffset));
3090#ifdef CONFIG_CIFS_DEBUG2
3091 cFYI(1,("revision %d type 0x%x ooffset 0x%x goffset 0x%x "
3092 "sacloffset 0x%x dacloffset 0x%x", pntsd->revision, pntsd->type,
3093 pntsd->osidoffset, pntsd->gsidoffset, pntsd->sacloffset,
3094 pntsd->dacloffset));
3095#endif
3096 parse_sid(owner_sid_ptr, end_of_acl);
3097 parse_sid(group_sid_ptr, end_of_acl);
3098
3099/* cifscred->uid = owner_sid_ptr->rid;
3100 cifscred->gid = group_sid_ptr->rid;
3101 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
3102 sizeof (struct cifs_sid));
3103 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
3104 sizeof (struct cifs_sid)); */
3105
3106 num_aces = cpu_to_le32(dacl_ptr->num_aces);
3107 cFYI(1, ("num aces %d", num_aces));
3108 if (num_aces > 0) {
3109 ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *),
3110 GFP_KERNEL);
3111 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
3112 GFP_KERNEL);
3113
3114/* cifscred->cecount = dacl_ptr->num_aces;
3115 cifscred->ntaces = kmalloc(num_aces *
3116 sizeof(struct cifs_ntace *), GFP_KERNEL);
3117 cifscred->aces = kmalloc(num_aces *
3118 sizeof(struct cifs_ace *), GFP_KERNEL);*/
3119
3120 acl_base = (char *)dacl_ptr;
3121 acl_size = sizeof(struct cifs_acl);
3122
3123 for (i = 0; i < num_aces; ++i) {
3124 ppntace[i] = (struct cifs_ntace *)
3125 (acl_base + acl_size);
3126 ppace[i] = (struct cifs_ace *)
3127 ((char *)ppntace[i] +
3128 sizeof(struct cifs_ntace));
3129
3130/* memcpy((void *)(&(cifscred->ntaces[i])),
3131 (void *)ntace_ptrptr[i],
3132 sizeof(struct cifs_ntace));
3133 memcpy((void *)(&(cifscred->aces[i])),
3134 (void *)ace_ptrptr[i],
3135 sizeof(struct cifs_ace)); */
3136
3137 acl_base = (char *)ppntace[i];
3138 acl_size = cpu_to_le32(ppntace[i]->size);
3139#ifdef CONFIG_CIFS_DEBUG2
3140 cFYI(1, ("ACE revision:%d", ppace[i]->revision));
3141 }
3142#endif
3143 kfree(ppace);
3144 kfree(ppntace);
3145 }
3146
3147 return (0);
Steve French0a4b92c2006-01-12 15:44:21 -08003148}
3149
3150/* Get Security Descriptor (by handle) from remote server for a file or dir */
3151int
3152CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French50c2f752007-07-13 00:33:32 +00003153 /* BB fix up return info */ char *acl_inf, const int buflen,
Steve French442aa312007-09-24 20:25:46 +00003154 const int acl_type)
Steve French0a4b92c2006-01-12 15:44:21 -08003155{
3156 int rc = 0;
3157 int buf_type = 0;
3158 QUERY_SEC_DESC_REQ * pSMB;
3159 struct kvec iov[1];
3160
3161 cFYI(1, ("GetCifsACL"));
3162
Steve French50c2f752007-07-13 00:33:32 +00003163 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003164 8 /* parm len */, tcon, (void **) &pSMB);
3165 if (rc)
3166 return rc;
3167
3168 pSMB->MaxParameterCount = cpu_to_le32(4);
3169 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3170 pSMB->MaxSetupCount = 0;
3171 pSMB->Fid = fid; /* file handle always le */
3172 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3173 CIFS_ACL_DACL);
3174 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3175 pSMB->hdr.smb_buf_length += 11;
3176 iov[0].iov_base = (char *)pSMB;
3177 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3178
3179 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
3180 cifs_stats_inc(&tcon->num_acl_get);
3181 if (rc) {
3182 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3183 } else { /* decode response */
Steve French442aa312007-09-24 20:25:46 +00003184 struct cifs_ntsd *psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08003185 __le32 * parm;
3186 int parm_len;
3187 int data_len;
3188 int acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003189 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08003190
3191/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003192 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French0a4b92c2006-01-12 15:44:21 -08003193 (char **)&psec_desc,
3194 &parm_len, &data_len);
Steve French790fe572007-07-07 19:25:05 +00003195 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003196 goto qsec_out;
3197 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3198
Steve French50c2f752007-07-13 00:33:32 +00003199 cERROR(1, ("smb %p parm %p data %p",
3200 pSMBr, parm, psec_desc)); /* BB removeme BB */
Steve French0a4b92c2006-01-12 15:44:21 -08003201
3202 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3203 rc = -EIO; /* bad smb */
3204 goto qsec_out;
3205 }
3206
3207/* BB check that data area is minimum length and as big as acl_len */
3208
3209 acl_len = le32_to_cpu(*(__le32 *)parm);
Steve French790fe572007-07-07 19:25:05 +00003210 /* BB check if (acl_len > bufsize) */
Steve French0a4b92c2006-01-12 15:44:21 -08003211
3212 parse_sec_desc(psec_desc, acl_len);
3213 }
3214qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003215 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003216 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003217 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003218 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003219/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003220 return rc;
3221}
3222
Steve French6b8edfe2005-08-23 20:26:03 -07003223/* Legacy Query Path Information call for lookup to old servers such
3224 as Win9x/WinME */
3225int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003226 const unsigned char *searchName,
3227 FILE_ALL_INFO *pFinfo,
3228 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003229{
3230 QUERY_INFORMATION_REQ * pSMB;
3231 QUERY_INFORMATION_RSP * pSMBr;
3232 int rc = 0;
3233 int bytes_returned;
3234 int name_len;
3235
Steve French50c2f752007-07-13 00:33:32 +00003236 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003237QInfRetry:
3238 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003239 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003240 if (rc)
3241 return rc;
3242
3243 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3244 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003245 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3246 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003247 name_len++; /* trailing null */
3248 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003249 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003250 name_len = strnlen(searchName, PATH_MAX);
3251 name_len++; /* trailing null */
3252 strncpy(pSMB->FileName, searchName, name_len);
3253 }
3254 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003255 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003256 pSMB->hdr.smb_buf_length += (__u16) name_len;
3257 pSMB->ByteCount = cpu_to_le16(name_len);
3258
3259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003260 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003261 if (rc) {
3262 cFYI(1, ("Send error in QueryInfo = %d", rc));
3263 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003264 struct timespec ts;
3265 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3266 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003267 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003268 ts.tv_nsec = 0;
3269 ts.tv_sec = time;
3270 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003271 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003272 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3273 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003274 pFinfo->AllocationSize =
3275 cpu_to_le64(le32_to_cpu(pSMBr->size));
3276 pFinfo->EndOfFile = pFinfo->AllocationSize;
3277 pFinfo->Attributes =
3278 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003279 } else
3280 rc = -EIO; /* bad buffer passed in */
3281
3282 cifs_buf_release(pSMB);
3283
3284 if (rc == -EAGAIN)
3285 goto QInfRetry;
3286
3287 return rc;
3288}
3289
3290
3291
3292
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293int
3294CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3295 const unsigned char *searchName,
3296 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003297 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003298 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299{
3300/* level 263 SMB_QUERY_FILE_ALL_INFO */
3301 TRANSACTION2_QPI_REQ *pSMB = NULL;
3302 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3303 int rc = 0;
3304 int bytes_returned;
3305 int name_len;
3306 __u16 params, byte_count;
3307
3308/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3309QPathInfoRetry:
3310 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3311 (void **) &pSMBr);
3312 if (rc)
3313 return rc;
3314
3315 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3316 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003317 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003318 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 name_len++; /* trailing null */
3320 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003321 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 name_len = strnlen(searchName, PATH_MAX);
3323 name_len++; /* trailing null */
3324 strncpy(pSMB->FileName, searchName, name_len);
3325 }
3326
Steve French50c2f752007-07-13 00:33:32 +00003327 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 pSMB->TotalDataCount = 0;
3329 pSMB->MaxParameterCount = cpu_to_le16(2);
3330 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3331 pSMB->MaxSetupCount = 0;
3332 pSMB->Reserved = 0;
3333 pSMB->Flags = 0;
3334 pSMB->Timeout = 0;
3335 pSMB->Reserved2 = 0;
3336 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003337 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 pSMB->DataCount = 0;
3339 pSMB->DataOffset = 0;
3340 pSMB->SetupCount = 1;
3341 pSMB->Reserved3 = 0;
3342 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3343 byte_count = params + 1 /* pad */ ;
3344 pSMB->TotalParameterCount = cpu_to_le16(params);
3345 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003346 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003347 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3348 else
3349 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 pSMB->Reserved4 = 0;
3351 pSMB->hdr.smb_buf_length += byte_count;
3352 pSMB->ByteCount = cpu_to_le16(byte_count);
3353
3354 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3355 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3356 if (rc) {
3357 cFYI(1, ("Send error in QPathInfo = %d", rc));
3358 } else { /* decode response */
3359 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3360
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003361 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3362 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003363 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003365 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003366 rc = -EIO; /* 24 or 26 expected but we do not read
3367 last field */
3368 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003369 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003371 if (legacy) /* we do not read the last field, EAsize,
3372 fortunately since it varies by subdialect
3373 and on Set vs. Get, is two bytes or 4
3374 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003375 size = sizeof(FILE_INFO_STANDARD);
3376 else
3377 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 memcpy((char *) pFindData,
3379 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003380 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 } else
3382 rc = -ENOMEM;
3383 }
3384 cifs_buf_release(pSMB);
3385 if (rc == -EAGAIN)
3386 goto QPathInfoRetry;
3387
3388 return rc;
3389}
3390
3391int
3392CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3393 const unsigned char *searchName,
3394 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003395 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396{
3397/* SMB_QUERY_FILE_UNIX_BASIC */
3398 TRANSACTION2_QPI_REQ *pSMB = NULL;
3399 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3400 int rc = 0;
3401 int bytes_returned = 0;
3402 int name_len;
3403 __u16 params, byte_count;
3404
3405 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3406UnixQPathInfoRetry:
3407 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3408 (void **) &pSMBr);
3409 if (rc)
3410 return rc;
3411
3412 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3413 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003414 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003415 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 name_len++; /* trailing null */
3417 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003418 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 name_len = strnlen(searchName, PATH_MAX);
3420 name_len++; /* trailing null */
3421 strncpy(pSMB->FileName, searchName, name_len);
3422 }
3423
Steve French50c2f752007-07-13 00:33:32 +00003424 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 pSMB->TotalDataCount = 0;
3426 pSMB->MaxParameterCount = cpu_to_le16(2);
3427 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003428 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 pSMB->MaxSetupCount = 0;
3430 pSMB->Reserved = 0;
3431 pSMB->Flags = 0;
3432 pSMB->Timeout = 0;
3433 pSMB->Reserved2 = 0;
3434 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003435 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 pSMB->DataCount = 0;
3437 pSMB->DataOffset = 0;
3438 pSMB->SetupCount = 1;
3439 pSMB->Reserved3 = 0;
3440 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3441 byte_count = params + 1 /* pad */ ;
3442 pSMB->TotalParameterCount = cpu_to_le16(params);
3443 pSMB->ParameterCount = pSMB->TotalParameterCount;
3444 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3445 pSMB->Reserved4 = 0;
3446 pSMB->hdr.smb_buf_length += byte_count;
3447 pSMB->ByteCount = cpu_to_le16(byte_count);
3448
3449 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3450 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3451 if (rc) {
3452 cFYI(1, ("Send error in QPathInfo = %d", rc));
3453 } else { /* decode response */
3454 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3455
3456 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003457 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3458 "Unix Extensions can be disabled on mount "
3459 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 rc = -EIO; /* bad smb */
3461 } else {
3462 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3463 memcpy((char *) pFindData,
3464 (char *) &pSMBr->hdr.Protocol +
3465 data_offset,
3466 sizeof (FILE_UNIX_BASIC_INFO));
3467 }
3468 }
3469 cifs_buf_release(pSMB);
3470 if (rc == -EAGAIN)
3471 goto UnixQPathInfoRetry;
3472
3473 return rc;
3474}
3475
3476#if 0 /* function unused at present */
3477int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3478 const char *searchName, FILE_ALL_INFO * findData,
3479 const struct nls_table *nls_codepage)
3480{
3481/* level 257 SMB_ */
3482 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3483 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3484 int rc = 0;
3485 int bytes_returned;
3486 int name_len;
3487 __u16 params, byte_count;
3488
3489 cFYI(1, ("In FindUnique"));
3490findUniqueRetry:
3491 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3492 (void **) &pSMBr);
3493 if (rc)
3494 return rc;
3495
3496 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3497 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003498 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3499 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 name_len++; /* trailing null */
3501 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003502 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 name_len = strnlen(searchName, PATH_MAX);
3504 name_len++; /* trailing null */
3505 strncpy(pSMB->FileName, searchName, name_len);
3506 }
3507
3508 params = 12 + name_len /* includes null */ ;
3509 pSMB->TotalDataCount = 0; /* no EAs */
3510 pSMB->MaxParameterCount = cpu_to_le16(2);
3511 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3512 pSMB->MaxSetupCount = 0;
3513 pSMB->Reserved = 0;
3514 pSMB->Flags = 0;
3515 pSMB->Timeout = 0;
3516 pSMB->Reserved2 = 0;
3517 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003518 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519 pSMB->DataCount = 0;
3520 pSMB->DataOffset = 0;
3521 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3522 pSMB->Reserved3 = 0;
3523 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3524 byte_count = params + 1 /* pad */ ;
3525 pSMB->TotalParameterCount = cpu_to_le16(params);
3526 pSMB->ParameterCount = pSMB->TotalParameterCount;
3527 pSMB->SearchAttributes =
3528 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3529 ATTR_DIRECTORY);
3530 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3531 pSMB->SearchFlags = cpu_to_le16(1);
3532 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3533 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3534 pSMB->hdr.smb_buf_length += byte_count;
3535 pSMB->ByteCount = cpu_to_le16(byte_count);
3536
3537 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3538 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3539
3540 if (rc) {
3541 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3542 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003543 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 /* BB fill in */
3545 }
3546
3547 cifs_buf_release(pSMB);
3548 if (rc == -EAGAIN)
3549 goto findUniqueRetry;
3550
3551 return rc;
3552}
3553#endif /* end unused (temporarily) function */
3554
3555/* xid, tcon, searchName and codepage are input parms, rest are returned */
3556int
3557CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003558 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003560 __u16 *pnetfid,
3561 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562{
3563/* level 257 SMB_ */
3564 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3565 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3566 T2_FFIRST_RSP_PARMS * parms;
3567 int rc = 0;
3568 int bytes_returned = 0;
3569 int name_len;
3570 __u16 params, byte_count;
3571
Steve French50c2f752007-07-13 00:33:32 +00003572 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573
3574findFirstRetry:
3575 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3576 (void **) &pSMBr);
3577 if (rc)
3578 return rc;
3579
3580 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3581 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003582 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003583 PATH_MAX, nls_codepage, remap);
3584 /* We can not add the asterik earlier in case
3585 it got remapped to 0xF03A as if it were part of the
3586 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003588 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003589 pSMB->FileName[name_len+1] = 0;
3590 pSMB->FileName[name_len+2] = '*';
3591 pSMB->FileName[name_len+3] = 0;
3592 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3594 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003595 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 } else { /* BB add check for overrun of SMB buf BB */
3597 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003599 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 free buffer exit; BB */
3601 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003602 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003603 pSMB->FileName[name_len+1] = '*';
3604 pSMB->FileName[name_len+2] = 0;
3605 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 }
3607
3608 params = 12 + name_len /* includes null */ ;
3609 pSMB->TotalDataCount = 0; /* no EAs */
3610 pSMB->MaxParameterCount = cpu_to_le16(10);
3611 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3612 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3613 pSMB->MaxSetupCount = 0;
3614 pSMB->Reserved = 0;
3615 pSMB->Flags = 0;
3616 pSMB->Timeout = 0;
3617 pSMB->Reserved2 = 0;
3618 byte_count = params + 1 /* pad */ ;
3619 pSMB->TotalParameterCount = cpu_to_le16(params);
3620 pSMB->ParameterCount = pSMB->TotalParameterCount;
3621 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003622 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3623 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 pSMB->DataCount = 0;
3625 pSMB->DataOffset = 0;
3626 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3627 pSMB->Reserved3 = 0;
3628 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3629 pSMB->SearchAttributes =
3630 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3631 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003632 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3633 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 CIFS_SEARCH_RETURN_RESUME);
3635 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3636
3637 /* BB what should we set StorageType to? Does it matter? BB */
3638 pSMB->SearchStorageType = 0;
3639 pSMB->hdr.smb_buf_length += byte_count;
3640 pSMB->ByteCount = cpu_to_le16(byte_count);
3641
3642 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3643 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003644 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645
Steve French88274812006-03-09 22:21:45 +00003646 if (rc) {/* BB add logic to retry regular search if Unix search
3647 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 /* BB Add code to handle unsupported level rc */
3649 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003650
Steve French88274812006-03-09 22:21:45 +00003651 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652
3653 /* BB eventually could optimize out free and realloc of buf */
3654 /* for this case */
3655 if (rc == -EAGAIN)
3656 goto findFirstRetry;
3657 } else { /* decode response */
3658 /* BB remember to free buffer if error BB */
3659 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003660 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3662 psrch_inf->unicode = TRUE;
3663 else
3664 psrch_inf->unicode = FALSE;
3665
3666 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003667 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003668 psrch_inf->srch_entries_start =
3669 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3672 le16_to_cpu(pSMBr->t2.ParameterOffset));
3673
Steve French790fe572007-07-07 19:25:05 +00003674 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 psrch_inf->endOfSearch = TRUE;
3676 else
3677 psrch_inf->endOfSearch = FALSE;
3678
Steve French50c2f752007-07-13 00:33:32 +00003679 psrch_inf->entries_in_buffer =
3680 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003681 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 *pnetfid = parms->SearchHandle;
3684 } else {
3685 cifs_buf_release(pSMB);
3686 }
3687 }
3688
3689 return rc;
3690}
3691
3692int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003693 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694{
3695 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3696 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3697 T2_FNEXT_RSP_PARMS * parms;
3698 char *response_data;
3699 int rc = 0;
3700 int bytes_returned, name_len;
3701 __u16 params, byte_count;
3702
3703 cFYI(1, ("In FindNext"));
3704
Steve French790fe572007-07-07 19:25:05 +00003705 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 return -ENOENT;
3707
3708 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3709 (void **) &pSMBr);
3710 if (rc)
3711 return rc;
3712
Steve French50c2f752007-07-13 00:33:32 +00003713 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 byte_count = 0;
3715 pSMB->TotalDataCount = 0; /* no EAs */
3716 pSMB->MaxParameterCount = cpu_to_le16(8);
3717 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003718 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3719 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 pSMB->MaxSetupCount = 0;
3721 pSMB->Reserved = 0;
3722 pSMB->Flags = 0;
3723 pSMB->Timeout = 0;
3724 pSMB->Reserved2 = 0;
3725 pSMB->ParameterOffset = cpu_to_le16(
3726 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3727 pSMB->DataCount = 0;
3728 pSMB->DataOffset = 0;
3729 pSMB->SetupCount = 1;
3730 pSMB->Reserved3 = 0;
3731 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3732 pSMB->SearchHandle = searchHandle; /* always kept as le */
3733 pSMB->SearchCount =
3734 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3736 pSMB->ResumeKey = psrch_inf->resume_key;
3737 pSMB->SearchFlags =
3738 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3739
3740 name_len = psrch_inf->resume_name_len;
3741 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003742 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3744 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003745 /* 14 byte parm len above enough for 2 byte null terminator */
3746 pSMB->ResumeFileName[name_len] = 0;
3747 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 } else {
3749 rc = -EINVAL;
3750 goto FNext2_err_exit;
3751 }
3752 byte_count = params + 1 /* pad */ ;
3753 pSMB->TotalParameterCount = cpu_to_le16(params);
3754 pSMB->ParameterCount = pSMB->TotalParameterCount;
3755 pSMB->hdr.smb_buf_length += byte_count;
3756 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003757
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3759 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003760 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 if (rc) {
3762 if (rc == -EBADF) {
3763 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003764 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 } else
3766 cFYI(1, ("FindNext returned = %d", rc));
3767 } else { /* decode response */
3768 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003769
Steve French790fe572007-07-07 19:25:05 +00003770 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 /* BB fixme add lock for file (srch_info) struct here */
3772 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3773 psrch_inf->unicode = TRUE;
3774 else
3775 psrch_inf->unicode = FALSE;
3776 response_data = (char *) &pSMBr->hdr.Protocol +
3777 le16_to_cpu(pSMBr->t2.ParameterOffset);
3778 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3779 response_data = (char *)&pSMBr->hdr.Protocol +
3780 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003781 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003782 cifs_small_buf_release(
3783 psrch_inf->ntwrk_buf_start);
3784 else
3785 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 psrch_inf->srch_entries_start = response_data;
3787 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003788 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003789 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 psrch_inf->endOfSearch = TRUE;
3791 else
3792 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003793 psrch_inf->entries_in_buffer =
3794 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 psrch_inf->index_of_last_entry +=
3796 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003797/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3798 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799
3800 /* BB fixme add unlock here */
3801 }
3802
3803 }
3804
3805 /* BB On error, should we leave previous search buf (and count and
3806 last entry fields) intact or free the previous one? */
3807
3808 /* Note: On -EAGAIN error only caller can retry on handle based calls
3809 since file handle passed in no longer valid */
3810FNext2_err_exit:
3811 if (rc != 0)
3812 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 return rc;
3814}
3815
3816int
Steve French50c2f752007-07-13 00:33:32 +00003817CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3818 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819{
3820 int rc = 0;
3821 FINDCLOSE_REQ *pSMB = NULL;
3822 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3823 int bytes_returned;
3824
3825 cFYI(1, ("In CIFSSMBFindClose"));
3826 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3827
3828 /* no sense returning error if session restarted
3829 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003830 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 return 0;
3832 if (rc)
3833 return rc;
3834
3835 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3836 pSMB->FileID = searchHandle;
3837 pSMB->ByteCount = 0;
3838 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3839 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3840 if (rc) {
3841 cERROR(1, ("Send error in FindClose = %d", rc));
3842 }
Steve Frencha4544342005-08-24 13:59:35 -07003843 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 cifs_small_buf_release(pSMB);
3845
3846 /* Since session is dead, search handle closed on server already */
3847 if (rc == -EAGAIN)
3848 rc = 0;
3849
3850 return rc;
3851}
3852
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853int
3854CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003855 const unsigned char *searchName,
3856 __u64 * inode_number,
3857 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858{
3859 int rc = 0;
3860 TRANSACTION2_QPI_REQ *pSMB = NULL;
3861 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3862 int name_len, bytes_returned;
3863 __u16 params, byte_count;
3864
Steve French50c2f752007-07-13 00:33:32 +00003865 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003866 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003867 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868
3869GetInodeNumberRetry:
3870 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003871 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 if (rc)
3873 return rc;
3874
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3876 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003877 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003878 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 name_len++; /* trailing null */
3880 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003881 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 name_len = strnlen(searchName, PATH_MAX);
3883 name_len++; /* trailing null */
3884 strncpy(pSMB->FileName, searchName, name_len);
3885 }
3886
3887 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3888 pSMB->TotalDataCount = 0;
3889 pSMB->MaxParameterCount = cpu_to_le16(2);
3890 /* BB find exact max data count below from sess structure BB */
3891 pSMB->MaxDataCount = cpu_to_le16(4000);
3892 pSMB->MaxSetupCount = 0;
3893 pSMB->Reserved = 0;
3894 pSMB->Flags = 0;
3895 pSMB->Timeout = 0;
3896 pSMB->Reserved2 = 0;
3897 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003898 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 pSMB->DataCount = 0;
3900 pSMB->DataOffset = 0;
3901 pSMB->SetupCount = 1;
3902 pSMB->Reserved3 = 0;
3903 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3904 byte_count = params + 1 /* pad */ ;
3905 pSMB->TotalParameterCount = cpu_to_le16(params);
3906 pSMB->ParameterCount = pSMB->TotalParameterCount;
3907 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3908 pSMB->Reserved4 = 0;
3909 pSMB->hdr.smb_buf_length += byte_count;
3910 pSMB->ByteCount = cpu_to_le16(byte_count);
3911
3912 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3913 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3914 if (rc) {
3915 cFYI(1, ("error %d in QueryInternalInfo", rc));
3916 } else {
3917 /* decode response */
3918 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3919 if (rc || (pSMBr->ByteCount < 2))
3920 /* BB also check enough total bytes returned */
3921 /* If rc should we check for EOPNOSUPP and
3922 disable the srvino flag? or in caller? */
3923 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003924 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3926 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003927 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003929 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3931 rc = -EIO;
3932 goto GetInodeNumOut;
3933 }
3934 pfinfo = (struct file_internal_info *)
3935 (data_offset + (char *) &pSMBr->hdr.Protocol);
3936 *inode_number = pfinfo->UniqueId;
3937 }
3938 }
3939GetInodeNumOut:
3940 cifs_buf_release(pSMB);
3941 if (rc == -EAGAIN)
3942 goto GetInodeNumberRetry;
3943 return rc;
3944}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945
3946int
3947CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3948 const unsigned char *searchName,
3949 unsigned char **targetUNCs,
3950 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003951 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952{
3953/* TRANS2_GET_DFS_REFERRAL */
3954 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3955 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003956 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 int rc = 0;
3958 int bytes_returned;
3959 int name_len;
3960 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003961 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 __u16 params, byte_count;
3963 *number_of_UNC_in_array = 0;
3964 *targetUNCs = NULL;
3965
3966 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3967 if (ses == NULL)
3968 return -ENODEV;
3969getDFSRetry:
3970 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3971 (void **) &pSMBr);
3972 if (rc)
3973 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003974
3975 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003976 but should never be null here anyway */
3977 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 pSMB->hdr.Tid = ses->ipc_tid;
3979 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003980 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003982 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984
3985 if (ses->capabilities & CAP_UNICODE) {
3986 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3987 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003988 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003989 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 name_len++; /* trailing null */
3991 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003992 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 name_len = strnlen(searchName, PATH_MAX);
3994 name_len++; /* trailing null */
3995 strncpy(pSMB->RequestFileName, searchName, name_len);
3996 }
3997
Steve French790fe572007-07-07 19:25:05 +00003998 if (ses->server) {
3999 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004000 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4001 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4002 }
4003
Steve French50c2f752007-07-13 00:33:32 +00004004 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004005
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 params = 2 /* level */ + name_len /*includes null */ ;
4007 pSMB->TotalDataCount = 0;
4008 pSMB->DataCount = 0;
4009 pSMB->DataOffset = 0;
4010 pSMB->MaxParameterCount = 0;
4011 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4012 pSMB->MaxSetupCount = 0;
4013 pSMB->Reserved = 0;
4014 pSMB->Flags = 0;
4015 pSMB->Timeout = 0;
4016 pSMB->Reserved2 = 0;
4017 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004018 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 pSMB->SetupCount = 1;
4020 pSMB->Reserved3 = 0;
4021 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4022 byte_count = params + 3 /* pad */ ;
4023 pSMB->ParameterCount = cpu_to_le16(params);
4024 pSMB->TotalParameterCount = pSMB->ParameterCount;
4025 pSMB->MaxReferralLevel = cpu_to_le16(3);
4026 pSMB->hdr.smb_buf_length += byte_count;
4027 pSMB->ByteCount = cpu_to_le16(byte_count);
4028
4029 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4030 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4031 if (rc) {
4032 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
4033 } else { /* decode response */
4034/* BB Add logic to parse referrals here */
4035 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4036
Steve French50c2f752007-07-13 00:33:32 +00004037 /* BB Also check if enough total bytes returned? */
4038 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 rc = -EIO; /* bad smb */
4040 else {
Steve French50c2f752007-07-13 00:33:32 +00004041 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
4043
4044 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00004045 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00004047 referrals =
4048 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 (8 /* sizeof start of data block */ +
4050 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00004051 (char *) &pSMBr->hdr.Protocol);
Steve Frenchc18c8422007-07-18 23:21:09 +00004052 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
Steve French63135e02007-07-17 17:34:02 +00004053 "for referral one refer size: 0x%x srv "
4054 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00004055 le16_to_cpu(pSMBr->NumberOfReferrals),
4056 le16_to_cpu(pSMBr->DFSFlags),
4057 le16_to_cpu(referrals->ReferralSize),
4058 le16_to_cpu(referrals->ServerType),
4059 le16_to_cpu(referrals->ReferralFlags),
4060 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 /* BB This field is actually two bytes in from start of
4062 data block so we could do safety check that DataBlock
4063 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00004064 *number_of_UNC_in_array =
4065 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066
4067 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00004068 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 *number_of_UNC_in_array = 1;
4070
4071 /* get the length of the strings describing refs */
4072 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00004073 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00004075 __u16 offset =
4076 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00004078 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 not try to copy any more */
4080 *number_of_UNC_in_array = i;
4081 break;
Steve French50c2f752007-07-13 00:33:32 +00004082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 temp = ((char *)referrals) + offset;
4084
4085 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00004086 name_len += UniStrnlen((wchar_t *)temp,
4087 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 } else {
Steve French50c2f752007-07-13 00:33:32 +00004089 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 }
4091 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004092 /* BB add check that referral pointer does
4093 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 }
4095 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004096 *targetUNCs =
4097 kmalloc(name_len+1+(*number_of_UNC_in_array),
4098 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004099 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 rc = -ENOMEM;
4101 goto GetDFSRefExit;
4102 }
4103 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004104 referrals = (struct dfs_referral_level_3 *)
4105 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 (char *) &pSMBr->hdr.Protocol);
4107
Steve French50c2f752007-07-13 00:33:32 +00004108 for (i = 0; i < *number_of_UNC_in_array; i++) {
4109 temp = ((char *)referrals) +
4110 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4112 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004113 (__le16 *) temp,
4114 name_len,
4115 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 } else {
Steve French50c2f752007-07-13 00:33:32 +00004117 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 }
4119 /* BB update target_uncs pointers */
4120 referrals++;
4121 }
4122 temp = *targetUNCs;
4123 temp[name_len] = 0;
4124 }
4125
4126 }
4127GetDFSRefExit:
4128 if (pSMB)
4129 cifs_buf_release(pSMB);
4130
4131 if (rc == -EAGAIN)
4132 goto getDFSRetry;
4133
4134 return rc;
4135}
4136
Steve French20962432005-09-21 22:05:57 -07004137/* Query File System Info such as free space to old servers such as Win 9x */
4138int
4139SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4140{
4141/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4142 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4143 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4144 FILE_SYSTEM_ALLOC_INFO *response_data;
4145 int rc = 0;
4146 int bytes_returned = 0;
4147 __u16 params, byte_count;
4148
4149 cFYI(1, ("OldQFSInfo"));
4150oldQFSInfoRetry:
4151 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4152 (void **) &pSMBr);
4153 if (rc)
4154 return rc;
4155 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4156 (void **) &pSMBr);
4157 if (rc)
4158 return rc;
4159
4160 params = 2; /* level */
4161 pSMB->TotalDataCount = 0;
4162 pSMB->MaxParameterCount = cpu_to_le16(2);
4163 pSMB->MaxDataCount = cpu_to_le16(1000);
4164 pSMB->MaxSetupCount = 0;
4165 pSMB->Reserved = 0;
4166 pSMB->Flags = 0;
4167 pSMB->Timeout = 0;
4168 pSMB->Reserved2 = 0;
4169 byte_count = params + 1 /* pad */ ;
4170 pSMB->TotalParameterCount = cpu_to_le16(params);
4171 pSMB->ParameterCount = pSMB->TotalParameterCount;
4172 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4173 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4174 pSMB->DataCount = 0;
4175 pSMB->DataOffset = 0;
4176 pSMB->SetupCount = 1;
4177 pSMB->Reserved3 = 0;
4178 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4179 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4180 pSMB->hdr.smb_buf_length += byte_count;
4181 pSMB->ByteCount = cpu_to_le16(byte_count);
4182
4183 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4184 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4185 if (rc) {
4186 cFYI(1, ("Send error in QFSInfo = %d", rc));
4187 } else { /* decode response */
4188 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4189
4190 if (rc || (pSMBr->ByteCount < 18))
4191 rc = -EIO; /* bad smb */
4192 else {
4193 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004194 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004195 pSMBr->ByteCount, data_offset));
4196
Steve French50c2f752007-07-13 00:33:32 +00004197 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004198 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4199 FSData->f_bsize =
4200 le16_to_cpu(response_data->BytesPerSector) *
4201 le32_to_cpu(response_data->
4202 SectorsPerAllocationUnit);
4203 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004204 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004205 FSData->f_bfree = FSData->f_bavail =
4206 le32_to_cpu(response_data->FreeAllocationUnits);
4207 cFYI(1,
4208 ("Blocks: %lld Free: %lld Block size %ld",
4209 (unsigned long long)FSData->f_blocks,
4210 (unsigned long long)FSData->f_bfree,
4211 FSData->f_bsize));
4212 }
4213 }
4214 cifs_buf_release(pSMB);
4215
4216 if (rc == -EAGAIN)
4217 goto oldQFSInfoRetry;
4218
4219 return rc;
4220}
4221
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222int
Steve French737b7582005-04-28 22:41:06 -07004223CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224{
4225/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4226 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4227 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4228 FILE_SYSTEM_INFO *response_data;
4229 int rc = 0;
4230 int bytes_returned = 0;
4231 __u16 params, byte_count;
4232
4233 cFYI(1, ("In QFSInfo"));
4234QFSInfoRetry:
4235 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4236 (void **) &pSMBr);
4237 if (rc)
4238 return rc;
4239
4240 params = 2; /* level */
4241 pSMB->TotalDataCount = 0;
4242 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004243 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 pSMB->MaxSetupCount = 0;
4245 pSMB->Reserved = 0;
4246 pSMB->Flags = 0;
4247 pSMB->Timeout = 0;
4248 pSMB->Reserved2 = 0;
4249 byte_count = params + 1 /* pad */ ;
4250 pSMB->TotalParameterCount = cpu_to_le16(params);
4251 pSMB->ParameterCount = pSMB->TotalParameterCount;
4252 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004253 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 pSMB->DataCount = 0;
4255 pSMB->DataOffset = 0;
4256 pSMB->SetupCount = 1;
4257 pSMB->Reserved3 = 0;
4258 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4259 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4260 pSMB->hdr.smb_buf_length += byte_count;
4261 pSMB->ByteCount = cpu_to_le16(byte_count);
4262
4263 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4264 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4265 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004266 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004268 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269
Steve French20962432005-09-21 22:05:57 -07004270 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 rc = -EIO; /* bad smb */
4272 else {
4273 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274
4275 response_data =
4276 (FILE_SYSTEM_INFO
4277 *) (((char *) &pSMBr->hdr.Protocol) +
4278 data_offset);
4279 FSData->f_bsize =
4280 le32_to_cpu(response_data->BytesPerSector) *
4281 le32_to_cpu(response_data->
4282 SectorsPerAllocationUnit);
4283 FSData->f_blocks =
4284 le64_to_cpu(response_data->TotalAllocationUnits);
4285 FSData->f_bfree = FSData->f_bavail =
4286 le64_to_cpu(response_data->FreeAllocationUnits);
4287 cFYI(1,
4288 ("Blocks: %lld Free: %lld Block size %ld",
4289 (unsigned long long)FSData->f_blocks,
4290 (unsigned long long)FSData->f_bfree,
4291 FSData->f_bsize));
4292 }
4293 }
4294 cifs_buf_release(pSMB);
4295
4296 if (rc == -EAGAIN)
4297 goto QFSInfoRetry;
4298
4299 return rc;
4300}
4301
4302int
Steve French737b7582005-04-28 22:41:06 -07004303CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304{
4305/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4306 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4307 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4308 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4309 int rc = 0;
4310 int bytes_returned = 0;
4311 __u16 params, byte_count;
4312
4313 cFYI(1, ("In QFSAttributeInfo"));
4314QFSAttributeRetry:
4315 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4316 (void **) &pSMBr);
4317 if (rc)
4318 return rc;
4319
4320 params = 2; /* level */
4321 pSMB->TotalDataCount = 0;
4322 pSMB->MaxParameterCount = cpu_to_le16(2);
4323 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4324 pSMB->MaxSetupCount = 0;
4325 pSMB->Reserved = 0;
4326 pSMB->Flags = 0;
4327 pSMB->Timeout = 0;
4328 pSMB->Reserved2 = 0;
4329 byte_count = params + 1 /* pad */ ;
4330 pSMB->TotalParameterCount = cpu_to_le16(params);
4331 pSMB->ParameterCount = pSMB->TotalParameterCount;
4332 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004333 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 pSMB->DataCount = 0;
4335 pSMB->DataOffset = 0;
4336 pSMB->SetupCount = 1;
4337 pSMB->Reserved3 = 0;
4338 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4339 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4340 pSMB->hdr.smb_buf_length += byte_count;
4341 pSMB->ByteCount = cpu_to_le16(byte_count);
4342
4343 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4344 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4345 if (rc) {
4346 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4347 } else { /* decode response */
4348 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4349
Steve French50c2f752007-07-13 00:33:32 +00004350 if (rc || (pSMBr->ByteCount < 13)) {
4351 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 rc = -EIO; /* bad smb */
4353 } else {
4354 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4355 response_data =
4356 (FILE_SYSTEM_ATTRIBUTE_INFO
4357 *) (((char *) &pSMBr->hdr.Protocol) +
4358 data_offset);
4359 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004360 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 }
4362 }
4363 cifs_buf_release(pSMB);
4364
4365 if (rc == -EAGAIN)
4366 goto QFSAttributeRetry;
4367
4368 return rc;
4369}
4370
4371int
Steve French737b7582005-04-28 22:41:06 -07004372CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373{
4374/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4375 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4376 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4377 FILE_SYSTEM_DEVICE_INFO *response_data;
4378 int rc = 0;
4379 int bytes_returned = 0;
4380 __u16 params, byte_count;
4381
4382 cFYI(1, ("In QFSDeviceInfo"));
4383QFSDeviceRetry:
4384 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4385 (void **) &pSMBr);
4386 if (rc)
4387 return rc;
4388
4389 params = 2; /* level */
4390 pSMB->TotalDataCount = 0;
4391 pSMB->MaxParameterCount = cpu_to_le16(2);
4392 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4393 pSMB->MaxSetupCount = 0;
4394 pSMB->Reserved = 0;
4395 pSMB->Flags = 0;
4396 pSMB->Timeout = 0;
4397 pSMB->Reserved2 = 0;
4398 byte_count = params + 1 /* pad */ ;
4399 pSMB->TotalParameterCount = cpu_to_le16(params);
4400 pSMB->ParameterCount = pSMB->TotalParameterCount;
4401 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004402 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403
4404 pSMB->DataCount = 0;
4405 pSMB->DataOffset = 0;
4406 pSMB->SetupCount = 1;
4407 pSMB->Reserved3 = 0;
4408 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4409 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4410 pSMB->hdr.smb_buf_length += byte_count;
4411 pSMB->ByteCount = cpu_to_le16(byte_count);
4412
4413 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4414 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4415 if (rc) {
4416 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4417 } else { /* decode response */
4418 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4419
4420 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4421 rc = -EIO; /* bad smb */
4422 else {
4423 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4424 response_data =
Steve French737b7582005-04-28 22:41:06 -07004425 (FILE_SYSTEM_DEVICE_INFO *)
4426 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 data_offset);
4428 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004429 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 }
4431 }
4432 cifs_buf_release(pSMB);
4433
4434 if (rc == -EAGAIN)
4435 goto QFSDeviceRetry;
4436
4437 return rc;
4438}
4439
4440int
Steve French737b7582005-04-28 22:41:06 -07004441CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442{
4443/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4444 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4445 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4446 FILE_SYSTEM_UNIX_INFO *response_data;
4447 int rc = 0;
4448 int bytes_returned = 0;
4449 __u16 params, byte_count;
4450
4451 cFYI(1, ("In QFSUnixInfo"));
4452QFSUnixRetry:
4453 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4454 (void **) &pSMBr);
4455 if (rc)
4456 return rc;
4457
4458 params = 2; /* level */
4459 pSMB->TotalDataCount = 0;
4460 pSMB->DataCount = 0;
4461 pSMB->DataOffset = 0;
4462 pSMB->MaxParameterCount = cpu_to_le16(2);
4463 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4464 pSMB->MaxSetupCount = 0;
4465 pSMB->Reserved = 0;
4466 pSMB->Flags = 0;
4467 pSMB->Timeout = 0;
4468 pSMB->Reserved2 = 0;
4469 byte_count = params + 1 /* pad */ ;
4470 pSMB->ParameterCount = cpu_to_le16(params);
4471 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004472 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4473 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 pSMB->SetupCount = 1;
4475 pSMB->Reserved3 = 0;
4476 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4477 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4478 pSMB->hdr.smb_buf_length += byte_count;
4479 pSMB->ByteCount = cpu_to_le16(byte_count);
4480
4481 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4482 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4483 if (rc) {
4484 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4485 } else { /* decode response */
4486 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4487
4488 if (rc || (pSMBr->ByteCount < 13)) {
4489 rc = -EIO; /* bad smb */
4490 } else {
4491 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4492 response_data =
4493 (FILE_SYSTEM_UNIX_INFO
4494 *) (((char *) &pSMBr->hdr.Protocol) +
4495 data_offset);
4496 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004497 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 }
4499 }
4500 cifs_buf_release(pSMB);
4501
4502 if (rc == -EAGAIN)
4503 goto QFSUnixRetry;
4504
4505
4506 return rc;
4507}
4508
Jeremy Allisonac670552005-06-22 17:26:35 -07004509int
Steve French45abc6e2005-06-23 13:42:03 -05004510CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004511{
4512/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4513 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4514 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4515 int rc = 0;
4516 int bytes_returned = 0;
4517 __u16 params, param_offset, offset, byte_count;
4518
4519 cFYI(1, ("In SETFSUnixInfo"));
4520SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004521 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004522 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4523 (void **) &pSMBr);
4524 if (rc)
4525 return rc;
4526
4527 params = 4; /* 2 bytes zero followed by info level. */
4528 pSMB->MaxSetupCount = 0;
4529 pSMB->Reserved = 0;
4530 pSMB->Flags = 0;
4531 pSMB->Timeout = 0;
4532 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004533 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4534 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004535 offset = param_offset + params;
4536
4537 pSMB->MaxParameterCount = cpu_to_le16(4);
4538 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4539 pSMB->SetupCount = 1;
4540 pSMB->Reserved3 = 0;
4541 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4542 byte_count = 1 /* pad */ + params + 12;
4543
4544 pSMB->DataCount = cpu_to_le16(12);
4545 pSMB->ParameterCount = cpu_to_le16(params);
4546 pSMB->TotalDataCount = pSMB->DataCount;
4547 pSMB->TotalParameterCount = pSMB->ParameterCount;
4548 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4549 pSMB->DataOffset = cpu_to_le16(offset);
4550
4551 /* Params. */
4552 pSMB->FileNum = 0;
4553 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4554
4555 /* Data. */
4556 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4557 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4558 pSMB->ClientUnixCap = cpu_to_le64(cap);
4559
4560 pSMB->hdr.smb_buf_length += byte_count;
4561 pSMB->ByteCount = cpu_to_le16(byte_count);
4562
4563 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4564 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4565 if (rc) {
4566 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4567 } else { /* decode response */
4568 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4569 if (rc) {
4570 rc = -EIO; /* bad smb */
4571 }
4572 }
4573 cifs_buf_release(pSMB);
4574
4575 if (rc == -EAGAIN)
4576 goto SETFSUnixRetry;
4577
4578 return rc;
4579}
4580
4581
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582
4583int
4584CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004585 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586{
4587/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4588 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4589 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4590 FILE_SYSTEM_POSIX_INFO *response_data;
4591 int rc = 0;
4592 int bytes_returned = 0;
4593 __u16 params, byte_count;
4594
4595 cFYI(1, ("In QFSPosixInfo"));
4596QFSPosixRetry:
4597 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4598 (void **) &pSMBr);
4599 if (rc)
4600 return rc;
4601
4602 params = 2; /* level */
4603 pSMB->TotalDataCount = 0;
4604 pSMB->DataCount = 0;
4605 pSMB->DataOffset = 0;
4606 pSMB->MaxParameterCount = cpu_to_le16(2);
4607 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4608 pSMB->MaxSetupCount = 0;
4609 pSMB->Reserved = 0;
4610 pSMB->Flags = 0;
4611 pSMB->Timeout = 0;
4612 pSMB->Reserved2 = 0;
4613 byte_count = params + 1 /* pad */ ;
4614 pSMB->ParameterCount = cpu_to_le16(params);
4615 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004616 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4617 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 pSMB->SetupCount = 1;
4619 pSMB->Reserved3 = 0;
4620 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4621 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4622 pSMB->hdr.smb_buf_length += byte_count;
4623 pSMB->ByteCount = cpu_to_le16(byte_count);
4624
4625 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4626 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4627 if (rc) {
4628 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4629 } else { /* decode response */
4630 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4631
4632 if (rc || (pSMBr->ByteCount < 13)) {
4633 rc = -EIO; /* bad smb */
4634 } else {
4635 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4636 response_data =
4637 (FILE_SYSTEM_POSIX_INFO
4638 *) (((char *) &pSMBr->hdr.Protocol) +
4639 data_offset);
4640 FSData->f_bsize =
4641 le32_to_cpu(response_data->BlockSize);
4642 FSData->f_blocks =
4643 le64_to_cpu(response_data->TotalBlocks);
4644 FSData->f_bfree =
4645 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004646 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 FSData->f_bavail = FSData->f_bfree;
4648 } else {
4649 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004650 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 }
Steve French790fe572007-07-07 19:25:05 +00004652 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004654 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004655 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004657 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 }
4659 }
4660 cifs_buf_release(pSMB);
4661
4662 if (rc == -EAGAIN)
4663 goto QFSPosixRetry;
4664
4665 return rc;
4666}
4667
4668
Steve French50c2f752007-07-13 00:33:32 +00004669/* We can not use write of zero bytes trick to
4670 set file size due to need for large file support. Also note that
4671 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 routine which is only needed to work around a sharing violation bug
4673 in Samba which this routine can run into */
4674
4675int
4676CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004677 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004678 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679{
4680 struct smb_com_transaction2_spi_req *pSMB = NULL;
4681 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4682 struct file_end_of_file_info *parm_data;
4683 int name_len;
4684 int rc = 0;
4685 int bytes_returned = 0;
4686 __u16 params, byte_count, data_count, param_offset, offset;
4687
4688 cFYI(1, ("In SetEOF"));
4689SetEOFRetry:
4690 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4691 (void **) &pSMBr);
4692 if (rc)
4693 return rc;
4694
4695 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4696 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004697 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004698 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 name_len++; /* trailing null */
4700 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004701 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 name_len = strnlen(fileName, PATH_MAX);
4703 name_len++; /* trailing null */
4704 strncpy(pSMB->FileName, fileName, name_len);
4705 }
4706 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004707 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004709 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 pSMB->MaxSetupCount = 0;
4711 pSMB->Reserved = 0;
4712 pSMB->Flags = 0;
4713 pSMB->Timeout = 0;
4714 pSMB->Reserved2 = 0;
4715 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004716 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004718 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004719 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4720 pSMB->InformationLevel =
4721 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4722 else
4723 pSMB->InformationLevel =
4724 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4725 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4727 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004728 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 else
4730 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004731 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 }
4733
4734 parm_data =
4735 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4736 offset);
4737 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4738 pSMB->DataOffset = cpu_to_le16(offset);
4739 pSMB->SetupCount = 1;
4740 pSMB->Reserved3 = 0;
4741 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4742 byte_count = 3 /* pad */ + params + data_count;
4743 pSMB->DataCount = cpu_to_le16(data_count);
4744 pSMB->TotalDataCount = pSMB->DataCount;
4745 pSMB->ParameterCount = cpu_to_le16(params);
4746 pSMB->TotalParameterCount = pSMB->ParameterCount;
4747 pSMB->Reserved4 = 0;
4748 pSMB->hdr.smb_buf_length += byte_count;
4749 parm_data->FileSize = cpu_to_le64(size);
4750 pSMB->ByteCount = cpu_to_le16(byte_count);
4751 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4752 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4753 if (rc) {
4754 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4755 }
4756
4757 cifs_buf_release(pSMB);
4758
4759 if (rc == -EAGAIN)
4760 goto SetEOFRetry;
4761
4762 return rc;
4763}
4764
4765int
Steve French50c2f752007-07-13 00:33:32 +00004766CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4767 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768{
4769 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4770 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4771 char *data_offset;
4772 struct file_end_of_file_info *parm_data;
4773 int rc = 0;
4774 int bytes_returned = 0;
4775 __u16 params, param_offset, offset, byte_count, count;
4776
4777 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4778 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004779 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4780
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 if (rc)
4782 return rc;
4783
Steve Frenchcd634992005-04-28 22:41:10 -07004784 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4785
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4787 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004788
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 params = 6;
4790 pSMB->MaxSetupCount = 0;
4791 pSMB->Reserved = 0;
4792 pSMB->Flags = 0;
4793 pSMB->Timeout = 0;
4794 pSMB->Reserved2 = 0;
4795 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4796 offset = param_offset + params;
4797
Steve French50c2f752007-07-13 00:33:32 +00004798 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799
4800 count = sizeof(struct file_end_of_file_info);
4801 pSMB->MaxParameterCount = cpu_to_le16(2);
4802 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4803 pSMB->SetupCount = 1;
4804 pSMB->Reserved3 = 0;
4805 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4806 byte_count = 3 /* pad */ + params + count;
4807 pSMB->DataCount = cpu_to_le16(count);
4808 pSMB->ParameterCount = cpu_to_le16(params);
4809 pSMB->TotalDataCount = pSMB->DataCount;
4810 pSMB->TotalParameterCount = pSMB->ParameterCount;
4811 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4812 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004813 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4814 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 pSMB->DataOffset = cpu_to_le16(offset);
4816 parm_data->FileSize = cpu_to_le64(size);
4817 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004818 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4820 pSMB->InformationLevel =
4821 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4822 else
4823 pSMB->InformationLevel =
4824 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004825 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4827 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004828 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 else
4830 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004831 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 }
4833 pSMB->Reserved4 = 0;
4834 pSMB->hdr.smb_buf_length += byte_count;
4835 pSMB->ByteCount = cpu_to_le16(byte_count);
4836 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4837 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4838 if (rc) {
4839 cFYI(1,
4840 ("Send error in SetFileInfo (SetFileSize) = %d",
4841 rc));
4842 }
4843
4844 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004845 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846
Steve French50c2f752007-07-13 00:33:32 +00004847 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 since file handle passed in no longer valid */
4849
4850 return rc;
4851}
4852
Steve French50c2f752007-07-13 00:33:32 +00004853/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 an open handle, rather than by pathname - this is awkward due to
4855 potential access conflicts on the open, but it is unavoidable for these
4856 old servers since the only other choice is to go from 100 nanosecond DCE
4857 time and resort to the original setpathinfo level which takes the ancient
4858 DOS time format with 2 second granularity */
4859int
Steve French50c2f752007-07-13 00:33:32 +00004860CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4861 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862{
4863 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4864 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4865 char *data_offset;
4866 int rc = 0;
4867 int bytes_returned = 0;
4868 __u16 params, param_offset, offset, byte_count, count;
4869
4870 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004871 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4872
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 if (rc)
4874 return rc;
4875
Steve Frenchcd634992005-04-28 22:41:10 -07004876 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4877
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 /* At this point there is no need to override the current pid
4879 with the pid of the opener, but that could change if we someday
4880 use an existing handle (rather than opening one on the fly) */
4881 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4882 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004883
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 params = 6;
4885 pSMB->MaxSetupCount = 0;
4886 pSMB->Reserved = 0;
4887 pSMB->Flags = 0;
4888 pSMB->Timeout = 0;
4889 pSMB->Reserved2 = 0;
4890 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4891 offset = param_offset + params;
4892
Steve French50c2f752007-07-13 00:33:32 +00004893 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894
Steve French26f57362007-08-30 22:09:15 +00004895 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 pSMB->MaxParameterCount = cpu_to_le16(2);
4897 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4898 pSMB->SetupCount = 1;
4899 pSMB->Reserved3 = 0;
4900 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4901 byte_count = 3 /* pad */ + params + count;
4902 pSMB->DataCount = cpu_to_le16(count);
4903 pSMB->ParameterCount = cpu_to_le16(params);
4904 pSMB->TotalDataCount = pSMB->DataCount;
4905 pSMB->TotalParameterCount = pSMB->ParameterCount;
4906 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4907 pSMB->DataOffset = cpu_to_le16(offset);
4908 pSMB->Fid = fid;
4909 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4910 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4911 else
4912 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4913 pSMB->Reserved4 = 0;
4914 pSMB->hdr.smb_buf_length += byte_count;
4915 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004916 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4918 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4919 if (rc) {
Steve French50c2f752007-07-13 00:33:32 +00004920 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921 }
4922
Steve Frenchcd634992005-04-28 22:41:10 -07004923 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924
Steve French50c2f752007-07-13 00:33:32 +00004925 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 since file handle passed in no longer valid */
4927
4928 return rc;
4929}
4930
4931
4932int
4933CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004934 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004935 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936{
4937 TRANSACTION2_SPI_REQ *pSMB = NULL;
4938 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4939 int name_len;
4940 int rc = 0;
4941 int bytes_returned = 0;
4942 char *data_offset;
4943 __u16 params, param_offset, offset, byte_count, count;
4944
4945 cFYI(1, ("In SetTimes"));
4946
4947SetTimesRetry:
4948 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4949 (void **) &pSMBr);
4950 if (rc)
4951 return rc;
4952
4953 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4954 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004955 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004956 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 name_len++; /* trailing null */
4958 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004959 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960 name_len = strnlen(fileName, PATH_MAX);
4961 name_len++; /* trailing null */
4962 strncpy(pSMB->FileName, fileName, name_len);
4963 }
4964
4965 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004966 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 pSMB->MaxParameterCount = cpu_to_le16(2);
4968 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4969 pSMB->MaxSetupCount = 0;
4970 pSMB->Reserved = 0;
4971 pSMB->Flags = 0;
4972 pSMB->Timeout = 0;
4973 pSMB->Reserved2 = 0;
4974 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004975 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976 offset = param_offset + params;
4977 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4978 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4979 pSMB->DataOffset = cpu_to_le16(offset);
4980 pSMB->SetupCount = 1;
4981 pSMB->Reserved3 = 0;
4982 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4983 byte_count = 3 /* pad */ + params + count;
4984
4985 pSMB->DataCount = cpu_to_le16(count);
4986 pSMB->ParameterCount = cpu_to_le16(params);
4987 pSMB->TotalDataCount = pSMB->DataCount;
4988 pSMB->TotalParameterCount = pSMB->ParameterCount;
4989 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4990 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4991 else
4992 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4993 pSMB->Reserved4 = 0;
4994 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004995 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 pSMB->ByteCount = cpu_to_le16(byte_count);
4997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4999 if (rc) {
5000 cFYI(1, ("SetPathInfo (times) returned %d", rc));
5001 }
5002
5003 cifs_buf_release(pSMB);
5004
5005 if (rc == -EAGAIN)
5006 goto SetTimesRetry;
5007
5008 return rc;
5009}
5010
5011/* Can not be used to set time stamps yet (due to old DOS time format) */
5012/* Can be used to set attributes */
5013#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5014 handling it anyway and NT4 was what we thought it would be needed for
5015 Do not delete it until we prove whether needed for Win9x though */
5016int
5017CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5018 __u16 dos_attrs, const struct nls_table *nls_codepage)
5019{
5020 SETATTR_REQ *pSMB = NULL;
5021 SETATTR_RSP *pSMBr = NULL;
5022 int rc = 0;
5023 int bytes_returned;
5024 int name_len;
5025
5026 cFYI(1, ("In SetAttrLegacy"));
5027
5028SetAttrLgcyRetry:
5029 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5030 (void **) &pSMBr);
5031 if (rc)
5032 return rc;
5033
5034 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5035 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005036 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 PATH_MAX, nls_codepage);
5038 name_len++; /* trailing null */
5039 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005040 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 name_len = strnlen(fileName, PATH_MAX);
5042 name_len++; /* trailing null */
5043 strncpy(pSMB->fileName, fileName, name_len);
5044 }
5045 pSMB->attr = cpu_to_le16(dos_attrs);
5046 pSMB->BufferFormat = 0x04;
5047 pSMB->hdr.smb_buf_length += name_len + 1;
5048 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5049 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5050 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5051 if (rc) {
5052 cFYI(1, ("Error in LegacySetAttr = %d", rc));
5053 }
5054
5055 cifs_buf_release(pSMB);
5056
5057 if (rc == -EAGAIN)
5058 goto SetAttrLgcyRetry;
5059
5060 return rc;
5061}
5062#endif /* temporarily unneeded SetAttr legacy function */
5063
5064int
5065CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00005066 char *fileName, __u64 mode, __u64 uid, __u64 gid,
5067 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07005068 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069{
5070 TRANSACTION2_SPI_REQ *pSMB = NULL;
5071 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5072 int name_len;
5073 int rc = 0;
5074 int bytes_returned = 0;
5075 FILE_UNIX_BASIC_INFO *data_offset;
5076 __u16 params, param_offset, offset, count, byte_count;
5077
5078 cFYI(1, ("In SetUID/GID/Mode"));
5079setPermsRetry:
5080 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5081 (void **) &pSMBr);
5082 if (rc)
5083 return rc;
5084
5085 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5086 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005087 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005088 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089 name_len++; /* trailing null */
5090 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005091 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092 name_len = strnlen(fileName, PATH_MAX);
5093 name_len++; /* trailing null */
5094 strncpy(pSMB->FileName, fileName, name_len);
5095 }
5096
5097 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005098 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099 pSMB->MaxParameterCount = cpu_to_le16(2);
5100 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5101 pSMB->MaxSetupCount = 0;
5102 pSMB->Reserved = 0;
5103 pSMB->Flags = 0;
5104 pSMB->Timeout = 0;
5105 pSMB->Reserved2 = 0;
5106 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005107 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 offset = param_offset + params;
5109 data_offset =
5110 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5111 offset);
5112 memset(data_offset, 0, count);
5113 pSMB->DataOffset = cpu_to_le16(offset);
5114 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5115 pSMB->SetupCount = 1;
5116 pSMB->Reserved3 = 0;
5117 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5118 byte_count = 3 /* pad */ + params + count;
5119 pSMB->ParameterCount = cpu_to_le16(params);
5120 pSMB->DataCount = cpu_to_le16(count);
5121 pSMB->TotalParameterCount = pSMB->ParameterCount;
5122 pSMB->TotalDataCount = pSMB->DataCount;
5123 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5124 pSMB->Reserved4 = 0;
5125 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005126 /* Samba server ignores set of file size to zero due to bugs in some
5127 older clients, but we should be precise - we use SetFileSize to
5128 set file size and do not want to truncate file size to zero
5129 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005130 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005131 data_offset->EndOfFile = NO_CHANGE_64;
5132 data_offset->NumOfBytes = NO_CHANGE_64;
5133 data_offset->LastStatusChange = NO_CHANGE_64;
5134 data_offset->LastAccessTime = NO_CHANGE_64;
5135 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 data_offset->Uid = cpu_to_le64(uid);
5137 data_offset->Gid = cpu_to_le64(gid);
5138 /* better to leave device as zero when it is */
5139 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5140 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5141 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005142
Steve French790fe572007-07-07 19:25:05 +00005143 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005145 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005147 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005149 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005151 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005153 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005155 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5157
5158
5159 pSMB->ByteCount = cpu_to_le16(byte_count);
5160 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5161 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5162 if (rc) {
5163 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5164 }
5165
5166 if (pSMB)
5167 cifs_buf_release(pSMB);
5168 if (rc == -EAGAIN)
5169 goto setPermsRetry;
5170 return rc;
5171}
5172
Steve French50c2f752007-07-13 00:33:32 +00005173int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005174 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005175 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005176 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177{
5178 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005179 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5180 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005181 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 int bytes_returned;
5183
Steve French50c2f752007-07-13 00:33:32 +00005184 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005186 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 if (rc)
5188 return rc;
5189
5190 pSMB->TotalParameterCount = 0 ;
5191 pSMB->TotalDataCount = 0;
5192 pSMB->MaxParameterCount = cpu_to_le32(2);
5193 /* BB find exact data count max from sess structure BB */
5194 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005195/* BB VERIFY verify which is correct for above BB */
5196 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5197 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5198
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 pSMB->MaxSetupCount = 4;
5200 pSMB->Reserved = 0;
5201 pSMB->ParameterOffset = 0;
5202 pSMB->DataCount = 0;
5203 pSMB->DataOffset = 0;
5204 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5205 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5206 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005207 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5209 pSMB->Reserved2 = 0;
5210 pSMB->CompletionFilter = cpu_to_le32(filter);
5211 pSMB->Fid = netfid; /* file handle always le */
5212 pSMB->ByteCount = 0;
5213
5214 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5215 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5216 if (rc) {
5217 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005218 } else {
5219 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005220 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005221 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005222 sizeof(struct dir_notify_req),
5223 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005224 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005225 dnotify_req->Pid = pSMB->hdr.Pid;
5226 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5227 dnotify_req->Mid = pSMB->hdr.Mid;
5228 dnotify_req->Tid = pSMB->hdr.Tid;
5229 dnotify_req->Uid = pSMB->hdr.Uid;
5230 dnotify_req->netfid = netfid;
5231 dnotify_req->pfile = pfile;
5232 dnotify_req->filter = filter;
5233 dnotify_req->multishot = multishot;
5234 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005235 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005236 &GlobalDnotifyReqList);
5237 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005238 } else
Steve French47c786e2005-10-11 20:03:18 -07005239 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 }
5241 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005242 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243}
5244#ifdef CONFIG_CIFS_XATTR
5245ssize_t
5246CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5247 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005248 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005249 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250{
5251 /* BB assumes one setup word */
5252 TRANSACTION2_QPI_REQ *pSMB = NULL;
5253 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5254 int rc = 0;
5255 int bytes_returned;
5256 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005257 struct fea *temp_fea;
5258 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259 __u16 params, byte_count;
5260
5261 cFYI(1, ("In Query All EAs path %s", searchName));
5262QAllEAsRetry:
5263 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5264 (void **) &pSMBr);
5265 if (rc)
5266 return rc;
5267
5268 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5269 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005270 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005271 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 name_len++; /* trailing null */
5273 name_len *= 2;
5274 } else { /* BB improve the check for buffer overruns BB */
5275 name_len = strnlen(searchName, PATH_MAX);
5276 name_len++; /* trailing null */
5277 strncpy(pSMB->FileName, searchName, name_len);
5278 }
5279
Steve French50c2f752007-07-13 00:33:32 +00005280 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 pSMB->TotalDataCount = 0;
5282 pSMB->MaxParameterCount = cpu_to_le16(2);
5283 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5284 pSMB->MaxSetupCount = 0;
5285 pSMB->Reserved = 0;
5286 pSMB->Flags = 0;
5287 pSMB->Timeout = 0;
5288 pSMB->Reserved2 = 0;
5289 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005290 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 pSMB->DataCount = 0;
5292 pSMB->DataOffset = 0;
5293 pSMB->SetupCount = 1;
5294 pSMB->Reserved3 = 0;
5295 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5296 byte_count = params + 1 /* pad */ ;
5297 pSMB->TotalParameterCount = cpu_to_le16(params);
5298 pSMB->ParameterCount = pSMB->TotalParameterCount;
5299 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5300 pSMB->Reserved4 = 0;
5301 pSMB->hdr.smb_buf_length += byte_count;
5302 pSMB->ByteCount = cpu_to_le16(byte_count);
5303
5304 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5305 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5306 if (rc) {
5307 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5308 } else { /* decode response */
5309 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5310
5311 /* BB also check enough total bytes returned */
5312 /* BB we need to improve the validity checking
5313 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005314 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 rc = -EIO; /* bad smb */
5316 /* else if (pFindData){
5317 memcpy((char *) pFindData,
5318 (char *) &pSMBr->hdr.Protocol +
5319 data_offset, kl);
5320 }*/ else {
5321 /* check that length of list is not more than bcc */
5322 /* check that each entry does not go beyond length
5323 of list */
5324 /* check that each element of each entry does not
5325 go beyond end of list */
5326 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005327 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328 rc = 0;
5329 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005330 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 ea_response_data = (struct fealist *)
5332 (((char *) &pSMBr->hdr.Protocol) +
5333 data_offset);
5334 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005335 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005336 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005337 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005338 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339 } else {
5340 /* account for ea list len */
5341 name_len -= 4;
5342 temp_fea = ea_response_data->list;
5343 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005344 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 __u16 value_len;
5346 name_len -= 4;
5347 temp_ptr += 4;
5348 rc += temp_fea->name_len;
5349 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005350 rc = rc + 5 + 1;
5351 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005352 memcpy(EAData, "user.", 5);
5353 EAData += 5;
5354 memcpy(EAData, temp_ptr,
5355 temp_fea->name_len);
5356 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357 /* null terminate name */
5358 *EAData = 0;
5359 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005360 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 /* skip copy - calc size only */
5362 } else {
5363 /* stop before overrun buffer */
5364 rc = -ERANGE;
5365 break;
5366 }
5367 name_len -= temp_fea->name_len;
5368 temp_ptr += temp_fea->name_len;
5369 /* account for trailing null */
5370 name_len--;
5371 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005372 value_len =
5373 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 name_len -= value_len;
5375 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005376 /* BB check that temp_ptr is still
5377 within the SMB BB*/
5378
5379 /* no trailing null to account for
5380 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 /* go on to next EA */
5382 temp_fea = (struct fea *)temp_ptr;
5383 }
5384 }
5385 }
5386 }
5387 if (pSMB)
5388 cifs_buf_release(pSMB);
5389 if (rc == -EAGAIN)
5390 goto QAllEAsRetry;
5391
5392 return (ssize_t)rc;
5393}
5394
Steve French50c2f752007-07-13 00:33:32 +00005395ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5396 const unsigned char *searchName, const unsigned char *ea_name,
5397 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005398 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399{
5400 TRANSACTION2_QPI_REQ *pSMB = NULL;
5401 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5402 int rc = 0;
5403 int bytes_returned;
5404 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005405 struct fea *temp_fea;
5406 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 __u16 params, byte_count;
5408
5409 cFYI(1, ("In Query EA path %s", searchName));
5410QEARetry:
5411 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5412 (void **) &pSMBr);
5413 if (rc)
5414 return rc;
5415
5416 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5417 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005418 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005419 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 name_len++; /* trailing null */
5421 name_len *= 2;
5422 } else { /* BB improve the check for buffer overruns BB */
5423 name_len = strnlen(searchName, PATH_MAX);
5424 name_len++; /* trailing null */
5425 strncpy(pSMB->FileName, searchName, name_len);
5426 }
5427
Steve French50c2f752007-07-13 00:33:32 +00005428 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 pSMB->TotalDataCount = 0;
5430 pSMB->MaxParameterCount = cpu_to_le16(2);
5431 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5432 pSMB->MaxSetupCount = 0;
5433 pSMB->Reserved = 0;
5434 pSMB->Flags = 0;
5435 pSMB->Timeout = 0;
5436 pSMB->Reserved2 = 0;
5437 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005438 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 pSMB->DataCount = 0;
5440 pSMB->DataOffset = 0;
5441 pSMB->SetupCount = 1;
5442 pSMB->Reserved3 = 0;
5443 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5444 byte_count = params + 1 /* pad */ ;
5445 pSMB->TotalParameterCount = cpu_to_le16(params);
5446 pSMB->ParameterCount = pSMB->TotalParameterCount;
5447 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5448 pSMB->Reserved4 = 0;
5449 pSMB->hdr.smb_buf_length += byte_count;
5450 pSMB->ByteCount = cpu_to_le16(byte_count);
5451
5452 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5453 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5454 if (rc) {
5455 cFYI(1, ("Send error in Query EA = %d", rc));
5456 } else { /* decode response */
5457 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5458
5459 /* BB also check enough total bytes returned */
5460 /* BB we need to improve the validity checking
5461 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005462 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 rc = -EIO; /* bad smb */
5464 /* else if (pFindData){
5465 memcpy((char *) pFindData,
5466 (char *) &pSMBr->hdr.Protocol +
5467 data_offset, kl);
5468 }*/ else {
5469 /* check that length of list is not more than bcc */
5470 /* check that each entry does not go beyond length
5471 of list */
5472 /* check that each element of each entry does not
5473 go beyond end of list */
5474 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005475 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 rc = -ENODATA;
5477 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005478 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 ea_response_data = (struct fealist *)
5480 (((char *) &pSMBr->hdr.Protocol) +
5481 data_offset);
5482 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005483 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005484 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005486 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 } else {
5488 /* account for ea list len */
5489 name_len -= 4;
5490 temp_fea = ea_response_data->list;
5491 temp_ptr = (char *)temp_fea;
5492 /* loop through checking if we have a matching
5493 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005494 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 __u16 value_len;
5496 name_len -= 4;
5497 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005498 value_len =
5499 le16_to_cpu(temp_fea->value_len);
5500 /* BB validate that value_len falls within SMB,
5501 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005502 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 temp_fea->name_len) == 0) {
5504 /* found a match */
5505 rc = value_len;
5506 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005507 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 memcpy(ea_value,
5509 temp_fea->name+temp_fea->name_len+1,
5510 rc);
Steve French50c2f752007-07-13 00:33:32 +00005511 /* ea values, unlike ea
5512 names, are not null
5513 terminated */
Steve French790fe572007-07-07 19:25:05 +00005514 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 /* skip copy - calc size only */
5516 } else {
Steve French50c2f752007-07-13 00:33:32 +00005517 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 rc = -ERANGE;
5519 }
5520 break;
5521 }
5522 name_len -= temp_fea->name_len;
5523 temp_ptr += temp_fea->name_len;
5524 /* account for trailing null */
5525 name_len--;
5526 temp_ptr++;
5527 name_len -= value_len;
5528 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005529 /* No trailing null to account for in
5530 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 temp_fea = (struct fea *)temp_ptr;
5532 }
Steve French50c2f752007-07-13 00:33:32 +00005533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 }
5535 }
5536 if (pSMB)
5537 cifs_buf_release(pSMB);
5538 if (rc == -EAGAIN)
5539 goto QEARetry;
5540
5541 return (ssize_t)rc;
5542}
5543
5544int
5545CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005546 const char *ea_name, const void *ea_value,
5547 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5548 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549{
5550 struct smb_com_transaction2_spi_req *pSMB = NULL;
5551 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5552 struct fealist *parm_data;
5553 int name_len;
5554 int rc = 0;
5555 int bytes_returned = 0;
5556 __u16 params, param_offset, byte_count, offset, count;
5557
5558 cFYI(1, ("In SetEA"));
5559SetEARetry:
5560 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5561 (void **) &pSMBr);
5562 if (rc)
5563 return rc;
5564
5565 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5566 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005567 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005568 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 name_len++; /* trailing null */
5570 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005571 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 name_len = strnlen(fileName, PATH_MAX);
5573 name_len++; /* trailing null */
5574 strncpy(pSMB->FileName, fileName, name_len);
5575 }
5576
5577 params = 6 + name_len;
5578
5579 /* done calculating parms using name_len of file name,
5580 now use name_len to calculate length of ea name
5581 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005582 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 name_len = 0;
5584 else
Steve French50c2f752007-07-13 00:33:32 +00005585 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586
5587 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5588 pSMB->MaxParameterCount = cpu_to_le16(2);
5589 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5590 pSMB->MaxSetupCount = 0;
5591 pSMB->Reserved = 0;
5592 pSMB->Flags = 0;
5593 pSMB->Timeout = 0;
5594 pSMB->Reserved2 = 0;
5595 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005596 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 offset = param_offset + params;
5598 pSMB->InformationLevel =
5599 cpu_to_le16(SMB_SET_FILE_EA);
5600
5601 parm_data =
5602 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5603 offset);
5604 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5605 pSMB->DataOffset = cpu_to_le16(offset);
5606 pSMB->SetupCount = 1;
5607 pSMB->Reserved3 = 0;
5608 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5609 byte_count = 3 /* pad */ + params + count;
5610 pSMB->DataCount = cpu_to_le16(count);
5611 parm_data->list_len = cpu_to_le32(count);
5612 parm_data->list[0].EA_flags = 0;
5613 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005614 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005616 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005617 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 parm_data->list[0].name[name_len] = 0;
5619 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5620 /* caller ensures that ea_value_len is less than 64K but
5621 we need to ensure that it fits within the smb */
5622
Steve French50c2f752007-07-13 00:33:32 +00005623 /*BB add length check to see if it would fit in
5624 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005625 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5626 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005627 memcpy(parm_data->list[0].name+name_len+1,
5628 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629
5630 pSMB->TotalDataCount = pSMB->DataCount;
5631 pSMB->ParameterCount = cpu_to_le16(params);
5632 pSMB->TotalParameterCount = pSMB->ParameterCount;
5633 pSMB->Reserved4 = 0;
5634 pSMB->hdr.smb_buf_length += byte_count;
5635 pSMB->ByteCount = cpu_to_le16(byte_count);
5636 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5637 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5638 if (rc) {
5639 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5640 }
5641
5642 cifs_buf_release(pSMB);
5643
5644 if (rc == -EAGAIN)
5645 goto SetEARetry;
5646
5647 return rc;
5648}
5649
5650#endif