blob: 59d7b7c037adafa4eac1357c62cc87eff1c1bcc7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French2dd29d32007-04-23 22:07:35 +00004 * Copyright (C) International Business Machines Corp., 2002,2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000037#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000062 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000063#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000064 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 {BAD_PROT, "\2"}
66};
67#endif
68
Steve French39798772006-05-31 22:40:51 +000069/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000072#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000073#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000087static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000096 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve French26f57362007-08-30 22:09:15 +000097 if (open_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 open_file->invalidHandle = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
105/* If the return code is zero, this function must fill in request_buf pointer */
106static int
107small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
108 void **request_buf /* returned */)
109{
110 int rc = 0;
111
112 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
113 check for tcp and smb session status done differently
114 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000115 if (tcon) {
116 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800117 /* only tree disconnect, open, and write,
118 (and ulogoff which does not have tcon)
119 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000120 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000121 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800122 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000123 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800124 smb_command));
125 return -ENODEV;
126 }
127 }
Steve French790fe572007-07-07 19:25:05 +0000128 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000129 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000131 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700132 reconnect, should be greater than cifs socket
133 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000134 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000135 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000137 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000138 CifsGood), 10 * HZ);
139 if (tcon->ses->server->tcpStatus ==
140 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000142 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000144 cFYI(1, ("gave up waiting on "
145 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700147 } /* else "hard" mount - keep retrying
148 until process is killed or server
149 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 } else /* TCP session is reestablished now */
151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Steve French50c2f752007-07-13 00:33:32 +0000153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 nls_codepage = load_nls_default();
155 /* need to prevent multiple threads trying to
156 simultaneously reconnect the same SMB session */
157 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000158 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000159 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700160 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000161 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000163 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000164 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000166 /* tell server which Unix caps we support */
167 if (tcon->ses->capabilities & CAP_UNIX)
168 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000169 tcon,
Steve French8af18972007-02-14 04:42:51 +0000170 NULL /* we do not know sb */,
Steve French50c2f752007-07-13 00:33:32 +0000171 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700172 /* BB FIXME add code to check if wsize needs
173 update due to negotiated smb buffer size
174 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000175 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 atomic_inc(&tconInfoReconnectCount);
177
178 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000179 /* Removed call to reopen open files here.
180 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700181 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Steve French50c2f752007-07-13 00:33:32 +0000183 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700184 know whether we can continue or not without
185 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000186 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 case SMB_COM_READ_ANDX:
188 case SMB_COM_WRITE_ANDX:
189 case SMB_COM_CLOSE:
190 case SMB_COM_FIND_CLOSE2:
191 case SMB_COM_LOCKING_ANDX: {
192 unload_nls(nls_codepage);
193 return -EAGAIN;
194 }
195 }
196 } else {
197 up(&tcon->ses->sesSem);
198 }
199 unload_nls(nls_codepage);
200
201 } else {
202 return -EIO;
203 }
204 }
Steve French790fe572007-07-07 19:25:05 +0000205 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 return rc;
207
208 *request_buf = cifs_small_buf_get();
209 if (*request_buf == NULL) {
210 /* BB should we add a retry in here if not a writepage? */
211 return -ENOMEM;
212 }
213
Steve French63135e02007-07-17 17:34:02 +0000214 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000215 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Steve French790fe572007-07-07 19:25:05 +0000217 if (tcon != NULL)
218 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000221}
222
Steve French12b3b8f2006-02-09 21:12:47 +0000223int
Steve French50c2f752007-07-13 00:33:32 +0000224small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000225 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000226{
227 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000228 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000229
Steve French5815449d2006-02-14 01:36:20 +0000230 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000231 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000232 return rc;
233
Steve French04fdabe2006-02-10 05:52:50 +0000234 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000235 buffer->Mid = GetNextMid(ses->server);
236 if (ses->capabilities & CAP_UNICODE)
237 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000238 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000239 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
240
241 /* uid, tid can stay at zero as set in header assemble */
242
Steve French50c2f752007-07-13 00:33:32 +0000243 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000244 this function is used after 1st of session setup requests */
245
246 return rc;
247}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
249/* If the return code is zero, this function must fill in request_buf pointer */
250static int
251smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
252 void **request_buf /* returned */ ,
253 void **response_buf /* returned */ )
254{
255 int rc = 0;
256
257 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
258 check for tcp and smb session status done differently
259 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000260 if (tcon) {
261 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800262 /* only tree disconnect, open, and write,
263 (and ulogoff which does not have tcon)
264 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000265 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800266 (smb_command != SMB_COM_OPEN_ANDX) &&
267 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000268 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800269 smb_command));
270 return -ENODEV;
271 }
272 }
273
Steve French790fe572007-07-07 19:25:05 +0000274 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000275 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700277 /* Give Demultiplex thread up to 10 seconds to
278 reconnect, should be greater than cifs socket
279 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000280 while (tcon->ses->server->tcpStatus ==
281 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000283 (tcon->ses->server->tcpStatus ==
284 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000285 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700286 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000288 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000290 cFYI(1, ("gave up waiting on "
291 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700293 } /* else "hard" mount - keep retrying
294 until process is killed or server
295 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 } else /* TCP session is reestablished now */
297 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 nls_codepage = load_nls_default();
300 /* need to prevent multiple threads trying to
301 simultaneously reconnect the same SMB session */
302 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000303 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000304 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700305 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000306 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700308 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
309 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000311 /* tell server which Unix caps we support */
312 if (tcon->ses->capabilities & CAP_UNIX)
313 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000314 tcon,
Steve French8af18972007-02-14 04:42:51 +0000315 NULL /* do not know sb */,
316 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700317 /* BB FIXME add code to check if wsize needs
318 update due to negotiated smb buffer size
319 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000320 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 atomic_inc(&tconInfoReconnectCount);
322
323 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000324 /* Removed call to reopen open files here.
325 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700326 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Steve French50c2f752007-07-13 00:33:32 +0000328 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700329 know whether we can continue or not without
330 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000331 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 case SMB_COM_READ_ANDX:
333 case SMB_COM_WRITE_ANDX:
334 case SMB_COM_CLOSE:
335 case SMB_COM_FIND_CLOSE2:
336 case SMB_COM_LOCKING_ANDX: {
337 unload_nls(nls_codepage);
338 return -EAGAIN;
339 }
340 }
341 } else {
342 up(&tcon->ses->sesSem);
343 }
344 unload_nls(nls_codepage);
345
346 } else {
347 return -EIO;
348 }
349 }
Steve French790fe572007-07-07 19:25:05 +0000350 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return rc;
352
353 *request_buf = cifs_buf_get();
354 if (*request_buf == NULL) {
355 /* BB should we add a retry in here if not a writepage? */
356 return -ENOMEM;
357 }
358 /* Although the original thought was we needed the response buf for */
359 /* potential retries of smb operations it turns out we can determine */
360 /* from the mid flags when the request buffer can be resent without */
361 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000362 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000363 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
366 wct /*wct */ );
367
Steve French790fe572007-07-07 19:25:05 +0000368 if (tcon != NULL)
369 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return rc;
372}
373
Steve French50c2f752007-07-13 00:33:32 +0000374static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376 int rc = -EINVAL;
377 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000378 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 /* check for plausible wct, bcc and t2 data and parm sizes */
381 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000382 if (pSMB->hdr.WordCount >= 10) {
383 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
385 /* check that bcc is at least as big as parms + data */
386 /* check that bcc is less than negotiated smb buffer */
387 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000388 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000389 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000390 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000392 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700393 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000395 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000396 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
398 return 0;
399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
401 }
402 }
Steve French50c2f752007-07-13 00:33:32 +0000403 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 sizeof(struct smb_t2_rsp) + 16);
405 return rc;
406}
407int
408CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
409{
410 NEGOTIATE_REQ *pSMB;
411 NEGOTIATE_RSP *pSMBr;
412 int rc = 0;
413 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000414 int i;
Steve French50c2f752007-07-13 00:33:32 +0000415 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000417 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100418 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Steve French790fe572007-07-07 19:25:05 +0000420 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 server = ses->server;
422 else {
423 rc = -EIO;
424 return rc;
425 }
426 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
427 (void **) &pSMB, (void **) &pSMBr);
428 if (rc)
429 return rc;
Steve French750d1152006-06-27 06:28:30 +0000430
431 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000432 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000433 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000434 else /* if override flags set only sign/seal OR them with global auth */
435 secFlags = extended_security | ses->overrideSecFlg;
436
Steve French762e5ab2007-06-28 18:41:42 +0000437 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000438
Steve French1982c342005-08-17 12:38:22 -0700439 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000440 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000441
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000442 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000443 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000444 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
445 cFYI(1, ("Kerberos only mechanism, enable extended security"));
446 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
447 }
Steve French50c2f752007-07-13 00:33:32 +0000448
Steve French39798772006-05-31 22:40:51 +0000449 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000450 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000451 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
452 count += strlen(protocols[i].name) + 1;
453 /* null at end of source and target buffers anyway */
454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 pSMB->hdr.smb_buf_length += count;
456 pSMB->ByteCount = cpu_to_le16(count);
457
458 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000460 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000461 goto neg_err_exit;
462
Al Viro733f99a2006-10-14 16:48:26 +0100463 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000464 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000465 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000466 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000467 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000468 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000469 could not negotiate a common dialect */
470 rc = -EOPNOTSUPP;
471 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000472#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000473 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100474 && ((dialect == LANMAN_PROT)
475 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000476 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000477 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000478
Steve French790fe572007-07-07 19:25:05 +0000479 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000480 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000481 server->secType = LANMAN;
482 else {
483 cERROR(1, ("mount failed weak security disabled"
484 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000485 rc = -EOPNOTSUPP;
486 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000487 }
Steve French254e55e2006-06-04 05:53:15 +0000488 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
489 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
490 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000491 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000492 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
493 /* even though we do not use raw we might as well set this
494 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000495 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000496 server->maxRw = 0xFF00;
497 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
498 } else {
499 server->maxRw = 0;/* we do not need to use raw anyway */
500 server->capabilities = CAP_MPX_MODE;
501 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000502 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000503 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000504 /* OS/2 often does not set timezone therefore
505 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000506 * Could deviate slightly from the right zone.
507 * Smallest defined timezone difference is 15 minutes
508 * (i.e. Nepal). Rounding up/down is done to match
509 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000510 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000511 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000512 struct timespec ts, utc;
513 utc = CURRENT_TIME;
514 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
515 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000516 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
517 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000518 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000519 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000520 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000521 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000522 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000523 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000524 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000525 if (val < 0)
Steve Frenchb815f1e2006-10-02 05:53:29 +0000526 result = - result;
527 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000528 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000529 server->timeAdj = (int)tmp;
530 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000531 }
Steve French790fe572007-07-07 19:25:05 +0000532 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000533
Steve French39798772006-05-31 22:40:51 +0000534
Steve French254e55e2006-06-04 05:53:15 +0000535 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000536 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000537
Steve French50c2f752007-07-13 00:33:32 +0000538 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000539 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000540 memcpy(server->cryptKey, rsp->EncryptionKey,
541 CIFS_CRYPTO_KEY_SIZE);
542 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
543 rc = -EIO; /* need cryptkey unless plain text */
544 goto neg_err_exit;
545 }
Steve French39798772006-05-31 22:40:51 +0000546
Steve French790fe572007-07-07 19:25:05 +0000547 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000548 /* we will not end up setting signing flags - as no signing
549 was in LANMAN and server did not return the flags on */
550 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000551#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000552 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000553 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000554 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000555 rc = -EOPNOTSUPP;
556#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000557 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000558 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000559 /* unknown wct */
560 rc = -EOPNOTSUPP;
561 goto neg_err_exit;
562 }
563 /* else wct == 17 NTLM */
564 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000565 if ((server->secMode & SECMODE_USER) == 0)
566 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000567
Steve French790fe572007-07-07 19:25:05 +0000568 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000569#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000570 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000571#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000572 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000573 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000574
Steve French790fe572007-07-07 19:25:05 +0000575 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000576 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000577 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000578 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000579 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000580 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000581 else if (secFlags & CIFSSEC_MAY_KRB5)
582 server->secType = Kerberos;
583 else if (secFlags & CIFSSEC_MAY_LANMAN)
584 server->secType = LANMAN;
585/* #ifdef CONFIG_CIFS_EXPERIMENTAL
586 else if (secFlags & CIFSSEC_MAY_PLNTXT)
587 server->secType = ??
588#endif */
589 else {
590 rc = -EOPNOTSUPP;
591 cERROR(1, ("Invalid security type"));
592 goto neg_err_exit;
593 }
594 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000595
Steve French254e55e2006-06-04 05:53:15 +0000596 /* one byte, so no need to convert this or EncryptionKeyLen from
597 little endian */
598 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
599 /* probably no need to store and check maxvcs */
600 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000602 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
603 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
604 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
605 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000606 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
607 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000608 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
609 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
610 CIFS_CRYPTO_KEY_SIZE);
611 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
612 && (pSMBr->EncryptionKeyLength == 0)) {
613 /* decode security blob */
614 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
615 rc = -EIO; /* no crypt key only if plain text pwd */
616 goto neg_err_exit;
617 }
618
619 /* BB might be helpful to save off the domain of server here */
620
Steve French50c2f752007-07-13 00:33:32 +0000621 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000622 (server->capabilities & CAP_EXTENDED_SECURITY)) {
623 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000624 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000626 goto neg_err_exit;
627 }
628
629 if (server->socketUseCount.counter > 1) {
630 if (memcmp(server->server_GUID,
631 pSMBr->u.extended_response.
632 GUID, 16) != 0) {
633 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000634 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000635 pSMBr->u.extended_response.GUID,
636 16);
637 }
638 } else
639 memcpy(server->server_GUID,
640 pSMBr->u.extended_response.GUID, 16);
641
642 if (count == 16) {
643 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000644 } else {
645 rc = decode_negTokenInit(pSMBr->u.extended_response.
646 SecurityBlob,
647 count - 16,
648 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000649 if (rc == 1) {
Jeff Laytone5459372007-11-03 05:11:06 +0000650 rc = 0;
Steve French254e55e2006-06-04 05:53:15 +0000651 } else {
652 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
Steve French254e55e2006-06-04 05:53:15 +0000655 } else
656 server->capabilities &= ~CAP_EXTENDED_SECURITY;
657
Steve French6344a422006-06-12 04:18:35 +0000658#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000659signing_check:
Steve French6344a422006-06-12 04:18:35 +0000660#endif
Steve French762e5ab2007-06-28 18:41:42 +0000661 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
662 /* MUST_SIGN already includes the MAY_SIGN FLAG
663 so if this is zero it means that signing is disabled */
664 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000665 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000666 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000667 "packet signing to be enabled in "
668 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000669 rc = -EOPNOTSUPP;
670 }
Steve French50c2f752007-07-13 00:33:32 +0000671 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000672 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000673 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
674 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000675 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000676 if ((server->secMode &
677 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
678 cERROR(1,
679 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000680 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000681 } else
682 server->secMode |= SECMODE_SIGN_REQUIRED;
683 } else {
684 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000685 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000686 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000687 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 }
Steve French50c2f752007-07-13 00:33:32 +0000689
690neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700691 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000692
Steve French790fe572007-07-07 19:25:05 +0000693 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 return rc;
695}
696
697int
698CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
699{
700 struct smb_hdr *smb_buffer;
701 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
702 int rc = 0;
703 int length;
704
705 cFYI(1, ("In tree disconnect"));
706 /*
707 * If last user of the connection and
708 * connection alive - disconnect it
709 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000710 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 * to be freed and kernel thread woken up).
712 */
713 if (tcon)
714 down(&tcon->tconSem);
715 else
716 return -EIO;
717
718 atomic_dec(&tcon->useCount);
719 if (atomic_read(&tcon->useCount) > 0) {
720 up(&tcon->tconSem);
721 return -EBUSY;
722 }
723
Steve French50c2f752007-07-13 00:33:32 +0000724 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000726 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000728 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 }
730
Steve French790fe572007-07-07 19:25:05 +0000731 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 up(&tcon->tconSem);
733 return -EIO;
734 }
Steve French50c2f752007-07-13 00:33:32 +0000735 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700736 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 if (rc) {
738 up(&tcon->tconSem);
739 return rc;
740 } else {
741 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
744 &length, 0);
745 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700746 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 if (smb_buffer)
749 cifs_small_buf_release(smb_buffer);
750 up(&tcon->tconSem);
751
Steve French50c2f752007-07-13 00:33:32 +0000752 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 closed on server already e.g. due to tcp session crashing */
754 if (rc == -EAGAIN)
755 rc = 0;
756
757 return rc;
758}
759
760int
761CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
762{
763 struct smb_hdr *smb_buffer_response;
764 LOGOFF_ANDX_REQ *pSMB;
765 int rc = 0;
766 int length;
767
768 cFYI(1, ("In SMBLogoff for session disconnect"));
769 if (ses)
770 down(&ses->sesSem);
771 else
772 return -EIO;
773
774 atomic_dec(&ses->inUse);
775 if (atomic_read(&ses->inUse) > 0) {
776 up(&ses->sesSem);
777 return -EBUSY;
778 }
779 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
780 if (rc) {
781 up(&ses->sesSem);
782 return rc;
783 }
784
785 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
Steve French50c2f752007-07-13 00:33:32 +0000786
Steve French790fe572007-07-07 19:25:05 +0000787 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700788 pSMB->hdr.Mid = GetNextMid(ses->server);
789
Steve French790fe572007-07-07 19:25:05 +0000790 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
792 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
793 }
794
795 pSMB->hdr.Uid = ses->Suid;
796
797 pSMB->AndXCommand = 0xFF;
798 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
799 smb_buffer_response, &length, 0);
800 if (ses->server) {
801 atomic_dec(&ses->server->socketUseCount);
802 if (atomic_read(&ses->server->socketUseCount) == 0) {
803 spin_lock(&GlobalMid_Lock);
804 ses->server->tcpStatus = CifsExiting;
805 spin_unlock(&GlobalMid_Lock);
806 rc = -ESHUTDOWN;
807 }
808 }
Steve Frencha59c6582005-08-17 12:12:19 -0700809 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700810 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000813 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 error */
815 if (rc == -EAGAIN)
816 rc = 0;
817 return rc;
818}
819
820int
Steve French2d785a52007-07-15 01:48:57 +0000821CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
822 __u16 type, const struct nls_table *nls_codepage, int remap)
823{
824 TRANSACTION2_SPI_REQ *pSMB = NULL;
825 TRANSACTION2_SPI_RSP *pSMBr = NULL;
826 struct unlink_psx_rq *pRqD;
827 int name_len;
828 int rc = 0;
829 int bytes_returned = 0;
830 __u16 params, param_offset, offset, byte_count;
831
832 cFYI(1, ("In POSIX delete"));
833PsxDelete:
834 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
835 (void **) &pSMBr);
836 if (rc)
837 return rc;
838
839 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
840 name_len =
841 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
842 PATH_MAX, nls_codepage, remap);
843 name_len++; /* trailing null */
844 name_len *= 2;
845 } else { /* BB add path length overrun check */
846 name_len = strnlen(fileName, PATH_MAX);
847 name_len++; /* trailing null */
848 strncpy(pSMB->FileName, fileName, name_len);
849 }
850
851 params = 6 + name_len;
852 pSMB->MaxParameterCount = cpu_to_le16(2);
853 pSMB->MaxDataCount = 0; /* BB double check this with jra */
854 pSMB->MaxSetupCount = 0;
855 pSMB->Reserved = 0;
856 pSMB->Flags = 0;
857 pSMB->Timeout = 0;
858 pSMB->Reserved2 = 0;
859 param_offset = offsetof(struct smb_com_transaction2_spi_req,
860 InformationLevel) - 4;
861 offset = param_offset + params;
862
863 /* Setup pointer to Request Data (inode type) */
864 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
865 pRqD->type = cpu_to_le16(type);
866 pSMB->ParameterOffset = cpu_to_le16(param_offset);
867 pSMB->DataOffset = cpu_to_le16(offset);
868 pSMB->SetupCount = 1;
869 pSMB->Reserved3 = 0;
870 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
871 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
872
873 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
874 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
875 pSMB->ParameterCount = cpu_to_le16(params);
876 pSMB->TotalParameterCount = pSMB->ParameterCount;
877 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
878 pSMB->Reserved4 = 0;
879 pSMB->hdr.smb_buf_length += byte_count;
880 pSMB->ByteCount = cpu_to_le16(byte_count);
881 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
882 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
883 if (rc) {
884 cFYI(1, ("Posix delete returned %d", rc));
885 }
886 cifs_buf_release(pSMB);
887
888 cifs_stats_inc(&tcon->num_deletes);
889
890 if (rc == -EAGAIN)
891 goto PsxDelete;
892
893 return rc;
894}
895
896int
Steve French737b7582005-04-28 22:41:06 -0700897CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
898 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899{
900 DELETE_FILE_REQ *pSMB = NULL;
901 DELETE_FILE_RSP *pSMBr = NULL;
902 int rc = 0;
903 int bytes_returned;
904 int name_len;
905
906DelFileRetry:
907 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
908 (void **) &pSMBr);
909 if (rc)
910 return rc;
911
912 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
913 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000914 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700915 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 name_len++; /* trailing null */
917 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700918 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 name_len = strnlen(fileName, PATH_MAX);
920 name_len++; /* trailing null */
921 strncpy(pSMB->fileName, fileName, name_len);
922 }
923 pSMB->SearchAttributes =
924 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
925 pSMB->BufferFormat = 0x04;
926 pSMB->hdr.smb_buf_length += name_len + 1;
927 pSMB->ByteCount = cpu_to_le16(name_len + 1);
928 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
929 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700930 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 if (rc) {
932 cFYI(1, ("Error in RMFile = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
935 cifs_buf_release(pSMB);
936 if (rc == -EAGAIN)
937 goto DelFileRetry;
938
939 return rc;
940}
941
942int
Steve French50c2f752007-07-13 00:33:32 +0000943CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700944 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945{
946 DELETE_DIRECTORY_REQ *pSMB = NULL;
947 DELETE_DIRECTORY_RSP *pSMBr = NULL;
948 int rc = 0;
949 int bytes_returned;
950 int name_len;
951
952 cFYI(1, ("In CIFSSMBRmDir"));
953RmDirRetry:
954 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
955 (void **) &pSMBr);
956 if (rc)
957 return rc;
958
959 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700960 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
961 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 name_len++; /* trailing null */
963 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700964 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 name_len = strnlen(dirName, PATH_MAX);
966 name_len++; /* trailing null */
967 strncpy(pSMB->DirName, dirName, name_len);
968 }
969
970 pSMB->BufferFormat = 0x04;
971 pSMB->hdr.smb_buf_length += name_len + 1;
972 pSMB->ByteCount = cpu_to_le16(name_len + 1);
973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700975 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 if (rc) {
977 cFYI(1, ("Error in RMDir = %d", rc));
978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980 cifs_buf_release(pSMB);
981 if (rc == -EAGAIN)
982 goto RmDirRetry;
983 return rc;
984}
985
986int
987CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700988 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989{
990 int rc = 0;
991 CREATE_DIRECTORY_REQ *pSMB = NULL;
992 CREATE_DIRECTORY_RSP *pSMBr = NULL;
993 int bytes_returned;
994 int name_len;
995
996 cFYI(1, ("In CIFSSMBMkDir"));
997MkDirRetry:
998 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
999 (void **) &pSMBr);
1000 if (rc)
1001 return rc;
1002
1003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00001004 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -07001005 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 name_len++; /* trailing null */
1007 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001008 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 name_len = strnlen(name, PATH_MAX);
1010 name_len++; /* trailing null */
1011 strncpy(pSMB->DirName, name, name_len);
1012 }
1013
1014 pSMB->BufferFormat = 0x04;
1015 pSMB->hdr.smb_buf_length += name_len + 1;
1016 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1017 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1018 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001019 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 if (rc) {
1021 cFYI(1, ("Error in Mkdir = %d", rc));
1022 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 cifs_buf_release(pSMB);
1025 if (rc == -EAGAIN)
1026 goto MkDirRetry;
1027 return rc;
1028}
1029
Steve French2dd29d32007-04-23 22:07:35 +00001030int
1031CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1032 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001033 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001034 const struct nls_table *nls_codepage, int remap)
1035{
1036 TRANSACTION2_SPI_REQ *pSMB = NULL;
1037 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1038 int name_len;
1039 int rc = 0;
1040 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001041 __u16 params, param_offset, offset, byte_count, count;
1042 OPEN_PSX_REQ * pdata;
1043 OPEN_PSX_RSP * psx_rsp;
1044
1045 cFYI(1, ("In POSIX Create"));
1046PsxCreat:
1047 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1048 (void **) &pSMBr);
1049 if (rc)
1050 return rc;
1051
1052 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1053 name_len =
1054 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1055 PATH_MAX, nls_codepage, remap);
1056 name_len++; /* trailing null */
1057 name_len *= 2;
1058 } else { /* BB improve the check for buffer overruns BB */
1059 name_len = strnlen(name, PATH_MAX);
1060 name_len++; /* trailing null */
1061 strncpy(pSMB->FileName, name, name_len);
1062 }
1063
1064 params = 6 + name_len;
1065 count = sizeof(OPEN_PSX_REQ);
1066 pSMB->MaxParameterCount = cpu_to_le16(2);
1067 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1068 pSMB->MaxSetupCount = 0;
1069 pSMB->Reserved = 0;
1070 pSMB->Flags = 0;
1071 pSMB->Timeout = 0;
1072 pSMB->Reserved2 = 0;
1073 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001074 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001075 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001076 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001077 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001078 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001079 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001080 pdata->OpenFlags = cpu_to_le32(*pOplock);
1081 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1082 pSMB->DataOffset = cpu_to_le16(offset);
1083 pSMB->SetupCount = 1;
1084 pSMB->Reserved3 = 0;
1085 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1086 byte_count = 3 /* pad */ + params + count;
1087
1088 pSMB->DataCount = cpu_to_le16(count);
1089 pSMB->ParameterCount = cpu_to_le16(params);
1090 pSMB->TotalDataCount = pSMB->DataCount;
1091 pSMB->TotalParameterCount = pSMB->ParameterCount;
1092 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1093 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001094 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001095 pSMB->ByteCount = cpu_to_le16(byte_count);
1096 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1097 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1098 if (rc) {
1099 cFYI(1, ("Posix create returned %d", rc));
1100 goto psx_create_err;
1101 }
1102
Steve French790fe572007-07-07 19:25:05 +00001103 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001104 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1105
1106 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1107 rc = -EIO; /* bad smb */
1108 goto psx_create_err;
1109 }
1110
1111 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001112 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001113 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001114
Steve French2dd29d32007-04-23 22:07:35 +00001115 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001116 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001117 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1118 /* Let caller know file was created so we can set the mode. */
1119 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001120 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001121 *pOplock |= CIFS_CREATE_ACTION;
1122 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001123 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1124 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001125#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001126 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001127#endif
1128 } else {
Steve French790fe572007-07-07 19:25:05 +00001129 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001130 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001131 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001132 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001133 goto psx_create_err;
1134 }
Steve French50c2f752007-07-13 00:33:32 +00001135 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001136 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001137 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001138 }
Steve French2dd29d32007-04-23 22:07:35 +00001139
1140psx_create_err:
1141 cifs_buf_release(pSMB);
1142
1143 cifs_stats_inc(&tcon->num_mkdirs);
1144
1145 if (rc == -EAGAIN)
1146 goto PsxCreat;
1147
Steve French50c2f752007-07-13 00:33:32 +00001148 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001149}
1150
Steve Frencha9d02ad2005-08-24 23:06:05 -07001151static __u16 convert_disposition(int disposition)
1152{
1153 __u16 ofun = 0;
1154
1155 switch (disposition) {
1156 case FILE_SUPERSEDE:
1157 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1158 break;
1159 case FILE_OPEN:
1160 ofun = SMBOPEN_OAPPEND;
1161 break;
1162 case FILE_CREATE:
1163 ofun = SMBOPEN_OCREATE;
1164 break;
1165 case FILE_OPEN_IF:
1166 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1167 break;
1168 case FILE_OVERWRITE:
1169 ofun = SMBOPEN_OTRUNC;
1170 break;
1171 case FILE_OVERWRITE_IF:
1172 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1173 break;
1174 default:
Steve French790fe572007-07-07 19:25:05 +00001175 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001176 ofun = SMBOPEN_OAPPEND; /* regular open */
1177 }
1178 return ofun;
1179}
1180
1181int
1182SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1183 const char *fileName, const int openDisposition,
1184 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001185 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001186 const struct nls_table *nls_codepage, int remap)
1187{
1188 int rc = -EACCES;
1189 OPENX_REQ *pSMB = NULL;
1190 OPENX_RSP *pSMBr = NULL;
1191 int bytes_returned;
1192 int name_len;
1193 __u16 count;
1194
1195OldOpenRetry:
1196 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1197 (void **) &pSMBr);
1198 if (rc)
1199 return rc;
1200
1201 pSMB->AndXCommand = 0xFF; /* none */
1202
1203 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1204 count = 1; /* account for one byte pad to word boundary */
1205 name_len =
1206 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1207 fileName, PATH_MAX, nls_codepage, remap);
1208 name_len++; /* trailing null */
1209 name_len *= 2;
1210 } else { /* BB improve check for buffer overruns BB */
1211 count = 0; /* no pad */
1212 name_len = strnlen(fileName, PATH_MAX);
1213 name_len++; /* trailing null */
1214 strncpy(pSMB->fileName, fileName, name_len);
1215 }
1216 if (*pOplock & REQ_OPLOCK)
1217 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001218 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001220
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1222 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1223 /* 0 = read
1224 1 = write
1225 2 = rw
1226 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001227 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001228 pSMB->Mode = cpu_to_le16(2);
1229 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1230 /* set file as system file if special file such
1231 as fifo and server expecting SFU style and
1232 no Unix extensions */
1233
Steve French790fe572007-07-07 19:25:05 +00001234 if (create_options & CREATE_OPTION_SPECIAL)
1235 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1236 else
Steve French3e87d802005-09-18 20:49:21 -07001237 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001238
1239 /* if ((omode & S_IWUGO) == 0)
1240 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1241 /* Above line causes problems due to vfs splitting create into two
1242 pieces - need to set mode after file created not while it is
1243 being created */
1244
1245 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001246/* pSMB->CreateOptions = cpu_to_le32(create_options &
1247 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001249
1250 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001251 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 count += name_len;
1253 pSMB->hdr.smb_buf_length += count;
1254
1255 pSMB->ByteCount = cpu_to_le16(count);
1256 /* long_op set to 1 to allow for oplock break timeouts */
1257 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00001258 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259 cifs_stats_inc(&tcon->num_opens);
1260 if (rc) {
1261 cFYI(1, ("Error in Open = %d", rc));
1262 } else {
1263 /* BB verify if wct == 15 */
1264
1265/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1266
1267 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1268 /* Let caller know file was created so we can set the mode. */
1269 /* Do we care about the CreateAction in any other cases? */
1270 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001271/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001272 *pOplock |= CIFS_CREATE_ACTION; */
1273 /* BB FIXME END */
1274
Steve French790fe572007-07-07 19:25:05 +00001275 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001276 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1277 pfile_info->LastAccessTime = 0; /* BB fixme */
1278 pfile_info->LastWriteTime = 0; /* BB fixme */
1279 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001280 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001281 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001282 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001283 pfile_info->AllocationSize =
1284 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1285 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001286 pfile_info->NumberOfLinks = cpu_to_le32(1);
1287 }
1288 }
1289
1290 cifs_buf_release(pSMB);
1291 if (rc == -EAGAIN)
1292 goto OldOpenRetry;
1293 return rc;
1294}
1295
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296int
1297CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1298 const char *fileName, const int openDisposition,
1299 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001300 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001301 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
1303 int rc = -EACCES;
1304 OPEN_REQ *pSMB = NULL;
1305 OPEN_RSP *pSMBr = NULL;
1306 int bytes_returned;
1307 int name_len;
1308 __u16 count;
1309
1310openRetry:
1311 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1312 (void **) &pSMBr);
1313 if (rc)
1314 return rc;
1315
1316 pSMB->AndXCommand = 0xFF; /* none */
1317
1318 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1319 count = 1; /* account for one byte pad to word boundary */
1320 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001321 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001322 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 name_len++; /* trailing null */
1324 name_len *= 2;
1325 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001326 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 count = 0; /* no pad */
1328 name_len = strnlen(fileName, PATH_MAX);
1329 name_len++; /* trailing null */
1330 pSMB->NameLength = cpu_to_le16(name_len);
1331 strncpy(pSMB->fileName, fileName, name_len);
1332 }
1333 if (*pOplock & REQ_OPLOCK)
1334 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001335 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1338 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001339 /* set file as system file if special file such
1340 as fifo and server expecting SFU style and
1341 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001342 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001343 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1344 else
1345 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 /* XP does not handle ATTR_POSIX_SEMANTICS */
1347 /* but it helps speed up case sensitive checks for other
1348 servers such as Samba */
1349 if (tcon->ses->capabilities & CAP_UNIX)
1350 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1351
1352 /* if ((omode & S_IWUGO) == 0)
1353 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1354 /* Above line causes problems due to vfs splitting create into two
1355 pieces - need to set mode after file created not while it is
1356 being created */
1357 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1358 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001359 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001360 /* BB Expirement with various impersonation levels and verify */
1361 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 pSMB->SecurityFlags =
1363 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1364
1365 count += name_len;
1366 pSMB->hdr.smb_buf_length += count;
1367
1368 pSMB->ByteCount = cpu_to_le16(count);
1369 /* long_op set to 1 to allow for oplock break timeouts */
1370 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1371 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001372 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 if (rc) {
1374 cFYI(1, ("Error in Open = %d", rc));
1375 } else {
Steve French09d1db52005-04-28 22:41:08 -07001376 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1378 /* Let caller know file was created so we can set the mode. */
1379 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001380 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001381 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001382 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001383 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 36 /* CreationTime to Attributes */);
1385 /* the file_info buf is endian converted by caller */
1386 pfile_info->AllocationSize = pSMBr->AllocationSize;
1387 pfile_info->EndOfFile = pSMBr->EndOfFile;
1388 pfile_info->NumberOfLinks = cpu_to_le32(1);
1389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001391
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 cifs_buf_release(pSMB);
1393 if (rc == -EAGAIN)
1394 goto openRetry;
1395 return rc;
1396}
1397
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398int
Steve French50c2f752007-07-13 00:33:32 +00001399CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1400 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1401 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402{
1403 int rc = -EACCES;
1404 READ_REQ *pSMB = NULL;
1405 READ_RSP *pSMBr = NULL;
1406 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001407 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001408 int resp_buf_type = 0;
1409 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
Steve French790fe572007-07-07 19:25:05 +00001411 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1412 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001413 wct = 12;
1414 else
1415 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
1417 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001418 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 if (rc)
1420 return rc;
1421
1422 /* tcon and ses pointer are checked in smb_init */
1423 if (tcon->ses->server == NULL)
1424 return -ECONNABORTED;
1425
Steve Frenchec637e32005-12-12 20:53:18 -08001426 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 pSMB->Fid = netfid;
1428 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001429 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001430 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001431 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001432 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001433
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 pSMB->Remaining = 0;
1435 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1436 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001437 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001438 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1439 else {
1440 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001441 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001442 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001443 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001444 }
Steve Frenchec637e32005-12-12 20:53:18 -08001445
1446 iov[0].iov_base = (char *)pSMB;
1447 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001448 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1449 &resp_buf_type, 0 /* not long op */, 1 /* log err */ );
Steve Frencha4544342005-08-24 13:59:35 -07001450 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001451 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 if (rc) {
1453 cERROR(1, ("Send error in read = %d", rc));
1454 } else {
1455 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1456 data_length = data_length << 16;
1457 data_length += le16_to_cpu(pSMBr->DataLength);
1458 *nbytes = data_length;
1459
1460 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001461 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001463 cFYI(1, ("bad length %d for count %d",
1464 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 rc = -EIO;
1466 *nbytes = 0;
1467 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001468 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001469 le16_to_cpu(pSMBr->DataOffset);
1470/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001471 cERROR(1,("Faulting on read rc = %d",rc));
1472 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001473 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001474 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001475 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 }
1477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
Steve French4b8f9302006-02-26 16:41:18 +00001479/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001480 if (*buf) {
1481 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001482 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001483 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001484 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001485 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001486 /* return buffer to caller to free */
1487 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001488 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001489 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001490 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001491 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001492 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001493
1494 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 since file handle passed in no longer valid */
1496 return rc;
1497}
1498
Steve Frenchec637e32005-12-12 20:53:18 -08001499
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500int
1501CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1502 const int netfid, const unsigned int count,
1503 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001504 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505{
1506 int rc = -EACCES;
1507 WRITE_REQ *pSMB = NULL;
1508 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001509 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 __u32 bytes_sent;
1511 __u16 byte_count;
1512
1513 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001514 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001515 return -ECONNABORTED;
1516
Steve French790fe572007-07-07 19:25:05 +00001517 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001518 wct = 14;
1519 else
1520 wct = 12;
1521
1522 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 (void **) &pSMBr);
1524 if (rc)
1525 return rc;
1526 /* tcon and ses pointer are checked in smb_init */
1527 if (tcon->ses->server == NULL)
1528 return -ECONNABORTED;
1529
1530 pSMB->AndXCommand = 0xFF; /* none */
1531 pSMB->Fid = netfid;
1532 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001533 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001534 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001535 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001536 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001537
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 pSMB->Reserved = 0xFFFFFFFF;
1539 pSMB->WriteMode = 0;
1540 pSMB->Remaining = 0;
1541
Steve French50c2f752007-07-13 00:33:32 +00001542 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 can send more if LARGE_WRITE_X capability returned by the server and if
1544 our buffer is big enough or if we convert to iovecs on socket writes
1545 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001546 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1548 } else {
1549 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1550 & ~0xFF;
1551 }
1552
1553 if (bytes_sent > count)
1554 bytes_sent = count;
1555 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001556 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001557 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001558 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001559 else if (ubuf) {
1560 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 cifs_buf_release(pSMB);
1562 return -EFAULT;
1563 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 /* No buffer */
1566 cifs_buf_release(pSMB);
1567 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001568 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001569 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001570 byte_count = bytes_sent + 1; /* pad */
1571 else /* wct == 12 */ {
1572 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1575 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001576 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001577
Steve French790fe572007-07-07 19:25:05 +00001578 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001579 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001580 else { /* old style write has byte count 4 bytes earlier
1581 so 4 bytes pad */
1582 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001583 (struct smb_com_writex_req *)pSMB;
1584 pSMBW->ByteCount = cpu_to_le16(byte_count);
1585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
1587 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1588 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001589 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 if (rc) {
1591 cFYI(1, ("Send error in write = %d", rc));
1592 *nbytes = 0;
1593 } else {
1594 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1595 *nbytes = (*nbytes) << 16;
1596 *nbytes += le16_to_cpu(pSMBr->Count);
1597 }
1598
1599 cifs_buf_release(pSMB);
1600
Steve French50c2f752007-07-13 00:33:32 +00001601 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 since file handle passed in no longer valid */
1603
1604 return rc;
1605}
1606
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001607int
1608CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001610 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1611 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612{
1613 int rc = -EACCES;
1614 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001615 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001616 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001617 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
Steve French790fe572007-07-07 19:25:05 +00001619 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001620
Steve French790fe572007-07-07 19:25:05 +00001621 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001622 wct = 14;
1623 else
1624 wct = 12;
1625 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 if (rc)
1627 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 /* tcon and ses pointer are checked in smb_init */
1629 if (tcon->ses->server == NULL)
1630 return -ECONNABORTED;
1631
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001632 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 pSMB->Fid = netfid;
1634 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001635 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001636 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001637 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001638 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 pSMB->Reserved = 0xFFFFFFFF;
1640 pSMB->WriteMode = 0;
1641 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001644 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
Steve French3e844692005-10-03 13:37:24 -07001646 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1647 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001648 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001649 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001650 pSMB->hdr.smb_buf_length += count+1;
1651 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001652 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1653 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001654 pSMB->ByteCount = cpu_to_le16(count + 1);
1655 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001656 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001657 (struct smb_com_writex_req *)pSMB;
1658 pSMBW->ByteCount = cpu_to_le16(count + 5);
1659 }
Steve French3e844692005-10-03 13:37:24 -07001660 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001661 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001662 iov[0].iov_len = smb_hdr_len + 4;
1663 else /* wct == 12 pad bigger by four bytes */
1664 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001665
Steve French3e844692005-10-03 13:37:24 -07001666
Steve Frenchec637e32005-12-12 20:53:18 -08001667 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve Frencha761ac52007-10-18 21:45:27 +00001668 long_op, 0 /* do not log STATUS code */ );
Steve Frencha4544342005-08-24 13:59:35 -07001669 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001671 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001673 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001674 /* presumably this can not happen, but best to be safe */
1675 rc = -EIO;
1676 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001677 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001678 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001679 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1680 *nbytes = (*nbytes) << 16;
1681 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
Steve French4b8f9302006-02-26 16:41:18 +00001684/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001685 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001686 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001687 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001688 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Steve French50c2f752007-07-13 00:33:32 +00001690 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 since file handle passed in no longer valid */
1692
1693 return rc;
1694}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001695
1696
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697int
1698CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1699 const __u16 smb_file_id, const __u64 len,
1700 const __u64 offset, const __u32 numUnlock,
1701 const __u32 numLock, const __u8 lockType, const int waitFlag)
1702{
1703 int rc = 0;
1704 LOCK_REQ *pSMB = NULL;
1705 LOCK_RSP *pSMBr = NULL;
1706 int bytes_returned;
1707 int timeout = 0;
1708 __u16 count;
1709
Steve French50c2f752007-07-13 00:33:32 +00001710 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001711 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1712
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 if (rc)
1714 return rc;
1715
Steve French46810cb2005-04-28 22:41:09 -07001716 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1717
Steve French790fe572007-07-07 19:25:05 +00001718 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 timeout = -1; /* no response expected */
1720 pSMB->Timeout = 0;
1721 } else if (waitFlag == TRUE) {
1722 timeout = 3; /* blocking operation, no timeout */
1723 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1724 } else {
1725 pSMB->Timeout = 0;
1726 }
1727
1728 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1729 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1730 pSMB->LockType = lockType;
1731 pSMB->AndXCommand = 0xFF; /* none */
1732 pSMB->Fid = smb_file_id; /* netfid stays le */
1733
Steve French790fe572007-07-07 19:25:05 +00001734 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1736 /* BB where to store pid high? */
1737 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1738 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1739 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1740 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1741 count = sizeof(LOCKING_ANDX_RANGE);
1742 } else {
1743 /* oplock break */
1744 count = 0;
1745 }
1746 pSMB->hdr.smb_buf_length += count;
1747 pSMB->ByteCount = cpu_to_le16(count);
1748
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001749 if (waitFlag) {
1750 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1751 (struct smb_hdr *) pSMBr, &bytes_returned);
1752 } else {
1753 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001755 }
Steve Frencha4544342005-08-24 13:59:35 -07001756 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if (rc) {
1758 cFYI(1, ("Send error in Lock = %d", rc));
1759 }
Steve French46810cb2005-04-28 22:41:09 -07001760 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
Steve French50c2f752007-07-13 00:33:32 +00001762 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 since file handle passed in no longer valid */
1764 return rc;
1765}
1766
1767int
Steve French08547b02006-02-28 22:39:25 +00001768CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1769 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001770 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001771 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001772{
1773 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1774 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001775 struct cifs_posix_lock *parm_data;
1776 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001777 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001778 int bytes_returned = 0;
1779 __u16 params, param_offset, offset, byte_count, count;
1780
1781 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001782
Steve French790fe572007-07-07 19:25:05 +00001783 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001784 return EINVAL;
1785
Steve French08547b02006-02-28 22:39:25 +00001786 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1787
1788 if (rc)
1789 return rc;
1790
1791 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1792
Steve French50c2f752007-07-13 00:33:32 +00001793 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001794 pSMB->MaxSetupCount = 0;
1795 pSMB->Reserved = 0;
1796 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001797 pSMB->Reserved2 = 0;
1798 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1799 offset = param_offset + params;
1800
Steve French08547b02006-02-28 22:39:25 +00001801 count = sizeof(struct cifs_posix_lock);
1802 pSMB->MaxParameterCount = cpu_to_le16(2);
1803 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1804 pSMB->SetupCount = 1;
1805 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001806 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001807 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1808 else
1809 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1810 byte_count = 3 /* pad */ + params + count;
1811 pSMB->DataCount = cpu_to_le16(count);
1812 pSMB->ParameterCount = cpu_to_le16(params);
1813 pSMB->TotalDataCount = pSMB->DataCount;
1814 pSMB->TotalParameterCount = pSMB->ParameterCount;
1815 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001816 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001817 (((char *) &pSMB->hdr.Protocol) + offset);
1818
1819 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001820 if (waitFlag) {
Steve French3a5ff612006-07-14 22:37:11 +00001821 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001822 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001823 pSMB->Timeout = cpu_to_le32(-1);
1824 } else
1825 pSMB->Timeout = 0;
1826
Steve French08547b02006-02-28 22:39:25 +00001827 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001828 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001829 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001830
1831 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001832 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001833 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1834 pSMB->Reserved4 = 0;
1835 pSMB->hdr.smb_buf_length += byte_count;
1836 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001837 if (waitFlag) {
1838 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1839 (struct smb_hdr *) pSMBr, &bytes_returned);
1840 } else {
1841 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001842 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001843 }
1844
Steve French08547b02006-02-28 22:39:25 +00001845 if (rc) {
1846 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001847 } else if (get_flag) {
1848 /* lock structure can be returned on get */
1849 __u16 data_offset;
1850 __u16 data_count;
1851 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001852
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001853 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1854 rc = -EIO; /* bad smb */
1855 goto plk_err_exit;
1856 }
Steve French790fe572007-07-07 19:25:05 +00001857 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001858 rc = -EINVAL;
1859 goto plk_err_exit;
1860 }
1861 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1862 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001863 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001864 rc = -EIO;
1865 goto plk_err_exit;
1866 }
1867 parm_data = (struct cifs_posix_lock *)
1868 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001869 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001870 pLockData->fl_type = F_UNLCK;
1871 }
Steve French50c2f752007-07-13 00:33:32 +00001872
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001873plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001874 if (pSMB)
1875 cifs_small_buf_release(pSMB);
1876
1877 /* Note: On -EAGAIN error only caller can retry on handle based calls
1878 since file handle passed in no longer valid */
1879
1880 return rc;
1881}
1882
1883
1884int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1886{
1887 int rc = 0;
1888 CLOSE_REQ *pSMB = NULL;
1889 CLOSE_RSP *pSMBr = NULL;
1890 int bytes_returned;
1891 cFYI(1, ("In CIFSSMBClose"));
1892
1893/* do not retry on dead session on close */
1894 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001895 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 return 0;
1897 if (rc)
1898 return rc;
1899
1900 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1901
1902 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001903 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 pSMB->ByteCount = 0;
1905 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1906 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001907 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001909 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 /* EINTR is expected when user ctl-c to kill app */
1911 cERROR(1, ("Send error in Close = %d", rc));
1912 }
1913 }
1914
1915 cifs_small_buf_release(pSMB);
1916
1917 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001918 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 rc = 0;
1920
1921 return rc;
1922}
1923
1924int
1925CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1926 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001927 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928{
1929 int rc = 0;
1930 RENAME_REQ *pSMB = NULL;
1931 RENAME_RSP *pSMBr = NULL;
1932 int bytes_returned;
1933 int name_len, name_len2;
1934 __u16 count;
1935
1936 cFYI(1, ("In CIFSSMBRename"));
1937renameRetry:
1938 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1939 (void **) &pSMBr);
1940 if (rc)
1941 return rc;
1942
1943 pSMB->BufferFormat = 0x04;
1944 pSMB->SearchAttributes =
1945 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1946 ATTR_DIRECTORY);
1947
1948 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1949 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001950 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001951 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 name_len++; /* trailing null */
1953 name_len *= 2;
1954 pSMB->OldFileName[name_len] = 0x04; /* pad */
1955 /* protocol requires ASCII signature byte on Unicode string */
1956 pSMB->OldFileName[name_len + 1] = 0x00;
1957 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001958 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001959 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1961 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001962 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 name_len = strnlen(fromName, PATH_MAX);
1964 name_len++; /* trailing null */
1965 strncpy(pSMB->OldFileName, fromName, name_len);
1966 name_len2 = strnlen(toName, PATH_MAX);
1967 name_len2++; /* trailing null */
1968 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1969 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1970 name_len2++; /* trailing null */
1971 name_len2++; /* signature byte */
1972 }
1973
1974 count = 1 /* 1st signature byte */ + name_len + name_len2;
1975 pSMB->hdr.smb_buf_length += count;
1976 pSMB->ByteCount = cpu_to_le16(count);
1977
1978 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1979 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001980 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 if (rc) {
1982 cFYI(1, ("Send error in rename = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +00001983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 cifs_buf_release(pSMB);
1986
1987 if (rc == -EAGAIN)
1988 goto renameRetry;
1989
1990 return rc;
1991}
1992
Steve French50c2f752007-07-13 00:33:32 +00001993int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1994 int netfid, char *target_name,
1995 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996{
1997 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1998 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001999 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 char *data_offset;
2001 char dummy_string[30];
2002 int rc = 0;
2003 int bytes_returned = 0;
2004 int len_of_str;
2005 __u16 params, param_offset, offset, count, byte_count;
2006
2007 cFYI(1, ("Rename to File by handle"));
2008 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2009 (void **) &pSMBr);
2010 if (rc)
2011 return rc;
2012
2013 params = 6;
2014 pSMB->MaxSetupCount = 0;
2015 pSMB->Reserved = 0;
2016 pSMB->Flags = 0;
2017 pSMB->Timeout = 0;
2018 pSMB->Reserved2 = 0;
2019 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2020 offset = param_offset + params;
2021
2022 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2023 rename_info = (struct set_file_rename *) data_offset;
2024 pSMB->MaxParameterCount = cpu_to_le16(2);
2025 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2026 pSMB->SetupCount = 1;
2027 pSMB->Reserved3 = 0;
2028 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2029 byte_count = 3 /* pad */ + params;
2030 pSMB->ParameterCount = cpu_to_le16(params);
2031 pSMB->TotalParameterCount = pSMB->ParameterCount;
2032 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2033 pSMB->DataOffset = cpu_to_le16(offset);
2034 /* construct random name ".cifs_tmp<inodenum><mid>" */
2035 rename_info->overwrite = cpu_to_le32(1);
2036 rename_info->root_fid = 0;
2037 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002038 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002039 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2040 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002041 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002043 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002044 target_name, PATH_MAX, nls_codepage,
2045 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 }
2047 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2048 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2049 byte_count += count;
2050 pSMB->DataCount = cpu_to_le16(count);
2051 pSMB->TotalDataCount = pSMB->DataCount;
2052 pSMB->Fid = netfid;
2053 pSMB->InformationLevel =
2054 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2055 pSMB->Reserved4 = 0;
2056 pSMB->hdr.smb_buf_length += byte_count;
2057 pSMB->ByteCount = cpu_to_le16(byte_count);
2058 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002059 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002060 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002062 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 }
Steve Frencha5a2b482005-08-20 21:42:53 -07002064
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 cifs_buf_release(pSMB);
2066
2067 /* Note: On -EAGAIN error only caller can retry on handle based calls
2068 since file handle passed in no longer valid */
2069
2070 return rc;
2071}
2072
2073int
Steve French50c2f752007-07-13 00:33:32 +00002074CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2075 const __u16 target_tid, const char *toName, const int flags,
2076 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077{
2078 int rc = 0;
2079 COPY_REQ *pSMB = NULL;
2080 COPY_RSP *pSMBr = NULL;
2081 int bytes_returned;
2082 int name_len, name_len2;
2083 __u16 count;
2084
2085 cFYI(1, ("In CIFSSMBCopy"));
2086copyRetry:
2087 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2088 (void **) &pSMBr);
2089 if (rc)
2090 return rc;
2091
2092 pSMB->BufferFormat = 0x04;
2093 pSMB->Tid2 = target_tid;
2094
2095 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2096
2097 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002098 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002099 fromName, PATH_MAX, nls_codepage,
2100 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 name_len++; /* trailing null */
2102 name_len *= 2;
2103 pSMB->OldFileName[name_len] = 0x04; /* pad */
2104 /* protocol requires ASCII signature byte on Unicode string */
2105 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002106 name_len2 =
2107 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002108 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2110 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002111 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 name_len = strnlen(fromName, PATH_MAX);
2113 name_len++; /* trailing null */
2114 strncpy(pSMB->OldFileName, fromName, name_len);
2115 name_len2 = strnlen(toName, PATH_MAX);
2116 name_len2++; /* trailing null */
2117 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2118 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2119 name_len2++; /* trailing null */
2120 name_len2++; /* signature byte */
2121 }
2122
2123 count = 1 /* 1st signature byte */ + name_len + name_len2;
2124 pSMB->hdr.smb_buf_length += count;
2125 pSMB->ByteCount = cpu_to_le16(count);
2126
2127 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2129 if (rc) {
2130 cFYI(1, ("Send error in copy = %d with %d files copied",
2131 rc, le16_to_cpu(pSMBr->CopyCount)));
2132 }
2133 if (pSMB)
2134 cifs_buf_release(pSMB);
2135
2136 if (rc == -EAGAIN)
2137 goto copyRetry;
2138
2139 return rc;
2140}
2141
2142int
2143CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2144 const char *fromName, const char *toName,
2145 const struct nls_table *nls_codepage)
2146{
2147 TRANSACTION2_SPI_REQ *pSMB = NULL;
2148 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2149 char *data_offset;
2150 int name_len;
2151 int name_len_target;
2152 int rc = 0;
2153 int bytes_returned = 0;
2154 __u16 params, param_offset, offset, byte_count;
2155
2156 cFYI(1, ("In Symlink Unix style"));
2157createSymLinkRetry:
2158 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2159 (void **) &pSMBr);
2160 if (rc)
2161 return rc;
2162
2163 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2164 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002165 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 /* find define for this maxpathcomponent */
2167 , nls_codepage);
2168 name_len++; /* trailing null */
2169 name_len *= 2;
2170
Steve French50c2f752007-07-13 00:33:32 +00002171 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 name_len = strnlen(fromName, PATH_MAX);
2173 name_len++; /* trailing null */
2174 strncpy(pSMB->FileName, fromName, name_len);
2175 }
2176 params = 6 + name_len;
2177 pSMB->MaxSetupCount = 0;
2178 pSMB->Reserved = 0;
2179 pSMB->Flags = 0;
2180 pSMB->Timeout = 0;
2181 pSMB->Reserved2 = 0;
2182 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002183 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 offset = param_offset + params;
2185
2186 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2187 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2188 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002189 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 /* find define for this maxpathcomponent */
2191 , nls_codepage);
2192 name_len_target++; /* trailing null */
2193 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002194 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 name_len_target = strnlen(toName, PATH_MAX);
2196 name_len_target++; /* trailing null */
2197 strncpy(data_offset, toName, name_len_target);
2198 }
2199
2200 pSMB->MaxParameterCount = cpu_to_le16(2);
2201 /* BB find exact max on data count below from sess */
2202 pSMB->MaxDataCount = cpu_to_le16(1000);
2203 pSMB->SetupCount = 1;
2204 pSMB->Reserved3 = 0;
2205 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2206 byte_count = 3 /* pad */ + params + name_len_target;
2207 pSMB->DataCount = cpu_to_le16(name_len_target);
2208 pSMB->ParameterCount = cpu_to_le16(params);
2209 pSMB->TotalDataCount = pSMB->DataCount;
2210 pSMB->TotalParameterCount = pSMB->ParameterCount;
2211 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2212 pSMB->DataOffset = cpu_to_le16(offset);
2213 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2214 pSMB->Reserved4 = 0;
2215 pSMB->hdr.smb_buf_length += byte_count;
2216 pSMB->ByteCount = cpu_to_le16(byte_count);
2217 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2218 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002219 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 if (rc) {
Steve French2d785a52007-07-15 01:48:57 +00002221 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 }
2223
2224 if (pSMB)
2225 cifs_buf_release(pSMB);
2226
2227 if (rc == -EAGAIN)
2228 goto createSymLinkRetry;
2229
2230 return rc;
2231}
2232
2233int
2234CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2235 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002236 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237{
2238 TRANSACTION2_SPI_REQ *pSMB = NULL;
2239 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2240 char *data_offset;
2241 int name_len;
2242 int name_len_target;
2243 int rc = 0;
2244 int bytes_returned = 0;
2245 __u16 params, param_offset, offset, byte_count;
2246
2247 cFYI(1, ("In Create Hard link Unix style"));
2248createHardLinkRetry:
2249 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2250 (void **) &pSMBr);
2251 if (rc)
2252 return rc;
2253
2254 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002255 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002256 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 name_len++; /* trailing null */
2258 name_len *= 2;
2259
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 = strnlen(toName, PATH_MAX);
2262 name_len++; /* trailing null */
2263 strncpy(pSMB->FileName, toName, name_len);
2264 }
2265 params = 6 + name_len;
2266 pSMB->MaxSetupCount = 0;
2267 pSMB->Reserved = 0;
2268 pSMB->Flags = 0;
2269 pSMB->Timeout = 0;
2270 pSMB->Reserved2 = 0;
2271 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002272 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 offset = param_offset + params;
2274
2275 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2276 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2277 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002278 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002279 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 name_len_target++; /* trailing null */
2281 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002282 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 name_len_target = strnlen(fromName, PATH_MAX);
2284 name_len_target++; /* trailing null */
2285 strncpy(data_offset, fromName, name_len_target);
2286 }
2287
2288 pSMB->MaxParameterCount = cpu_to_le16(2);
2289 /* BB find exact max on data count below from sess*/
2290 pSMB->MaxDataCount = cpu_to_le16(1000);
2291 pSMB->SetupCount = 1;
2292 pSMB->Reserved3 = 0;
2293 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2294 byte_count = 3 /* pad */ + params + name_len_target;
2295 pSMB->ParameterCount = cpu_to_le16(params);
2296 pSMB->TotalParameterCount = pSMB->ParameterCount;
2297 pSMB->DataCount = cpu_to_le16(name_len_target);
2298 pSMB->TotalDataCount = pSMB->DataCount;
2299 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2300 pSMB->DataOffset = cpu_to_le16(offset);
2301 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2302 pSMB->Reserved4 = 0;
2303 pSMB->hdr.smb_buf_length += byte_count;
2304 pSMB->ByteCount = cpu_to_le16(byte_count);
2305 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2306 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002307 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 if (rc) {
2309 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2310 }
2311
2312 cifs_buf_release(pSMB);
2313 if (rc == -EAGAIN)
2314 goto createHardLinkRetry;
2315
2316 return rc;
2317}
2318
2319int
2320CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2321 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002322 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323{
2324 int rc = 0;
2325 NT_RENAME_REQ *pSMB = NULL;
2326 RENAME_RSP *pSMBr = NULL;
2327 int bytes_returned;
2328 int name_len, name_len2;
2329 __u16 count;
2330
2331 cFYI(1, ("In CIFSCreateHardLink"));
2332winCreateHardLinkRetry:
2333
2334 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2335 (void **) &pSMBr);
2336 if (rc)
2337 return rc;
2338
2339 pSMB->SearchAttributes =
2340 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2341 ATTR_DIRECTORY);
2342 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2343 pSMB->ClusterCount = 0;
2344
2345 pSMB->BufferFormat = 0x04;
2346
2347 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2348 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002349 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002350 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 name_len++; /* trailing null */
2352 name_len *= 2;
2353 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002354 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002356 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002357 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2359 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002360 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 name_len = strnlen(fromName, PATH_MAX);
2362 name_len++; /* trailing null */
2363 strncpy(pSMB->OldFileName, fromName, name_len);
2364 name_len2 = strnlen(toName, PATH_MAX);
2365 name_len2++; /* trailing null */
2366 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2367 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2368 name_len2++; /* trailing null */
2369 name_len2++; /* signature byte */
2370 }
2371
2372 count = 1 /* string type byte */ + name_len + name_len2;
2373 pSMB->hdr.smb_buf_length += count;
2374 pSMB->ByteCount = cpu_to_le16(count);
2375
2376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2377 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002378 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 if (rc) {
2380 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2381 }
2382 cifs_buf_release(pSMB);
2383 if (rc == -EAGAIN)
2384 goto winCreateHardLinkRetry;
2385
2386 return rc;
2387}
2388
2389int
2390CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2391 const unsigned char *searchName,
2392 char *symlinkinfo, const int buflen,
2393 const struct nls_table *nls_codepage)
2394{
2395/* SMB_QUERY_FILE_UNIX_LINK */
2396 TRANSACTION2_QPI_REQ *pSMB = NULL;
2397 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2398 int rc = 0;
2399 int bytes_returned;
2400 int name_len;
2401 __u16 params, byte_count;
2402
2403 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2404
2405querySymLinkRetry:
2406 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2407 (void **) &pSMBr);
2408 if (rc)
2409 return rc;
2410
2411 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2412 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002413 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2414 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 name_len++; /* trailing null */
2416 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002417 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 name_len = strnlen(searchName, PATH_MAX);
2419 name_len++; /* trailing null */
2420 strncpy(pSMB->FileName, searchName, name_len);
2421 }
2422
2423 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2424 pSMB->TotalDataCount = 0;
2425 pSMB->MaxParameterCount = cpu_to_le16(2);
2426 /* BB find exact max data count below from sess structure BB */
2427 pSMB->MaxDataCount = cpu_to_le16(4000);
2428 pSMB->MaxSetupCount = 0;
2429 pSMB->Reserved = 0;
2430 pSMB->Flags = 0;
2431 pSMB->Timeout = 0;
2432 pSMB->Reserved2 = 0;
2433 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002434 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 pSMB->DataCount = 0;
2436 pSMB->DataOffset = 0;
2437 pSMB->SetupCount = 1;
2438 pSMB->Reserved3 = 0;
2439 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2440 byte_count = params + 1 /* pad */ ;
2441 pSMB->TotalParameterCount = cpu_to_le16(params);
2442 pSMB->ParameterCount = pSMB->TotalParameterCount;
2443 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2444 pSMB->Reserved4 = 0;
2445 pSMB->hdr.smb_buf_length += byte_count;
2446 pSMB->ByteCount = cpu_to_le16(byte_count);
2447
2448 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2449 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2450 if (rc) {
2451 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2452 } else {
2453 /* decode response */
2454
2455 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2456 if (rc || (pSMBr->ByteCount < 2))
2457 /* BB also check enough total bytes returned */
2458 rc = -EIO; /* bad smb */
2459 else {
2460 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2461 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2462
2463 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2464 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002465 &pSMBr->hdr.Protocol + data_offset),
2466 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002467 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002469 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2470 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 name_len, nls_codepage);
2472 } else {
2473 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002474 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 data_offset,
2476 min_t(const int, buflen, count));
2477 }
2478 symlinkinfo[buflen] = 0;
2479 /* just in case so calling code does not go off the end of buffer */
2480 }
2481 }
2482 cifs_buf_release(pSMB);
2483 if (rc == -EAGAIN)
2484 goto querySymLinkRetry;
2485 return rc;
2486}
2487
Parag Warudkarc9489772007-10-23 18:09:48 +00002488#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002489/* Initialize NT TRANSACT SMB into small smb request buffer.
2490 This assumes that all NT TRANSACTS that we init here have
2491 total parm and data under about 400 bytes (to fit in small cifs
2492 buffer size), which is the case so far, it easily fits. NB:
2493 Setup words themselves and ByteCount
2494 MaxSetupCount (size of returned setup area) and
2495 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002496static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002497smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002498 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002499 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002500{
2501 int rc;
2502 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002503 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002504
2505 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2506 (void **)&pSMB);
2507 if (rc)
2508 return rc;
2509 *ret_buf = (void *)pSMB;
2510 pSMB->Reserved = 0;
2511 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2512 pSMB->TotalDataCount = 0;
2513 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2514 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2515 pSMB->ParameterCount = pSMB->TotalParameterCount;
2516 pSMB->DataCount = pSMB->TotalDataCount;
2517 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2518 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2519 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2520 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2521 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2522 pSMB->SubCommand = cpu_to_le16(sub_command);
2523 return 0;
2524}
2525
2526static int
Steve French50c2f752007-07-13 00:33:32 +00002527validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002528 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002529{
Steve French50c2f752007-07-13 00:33:32 +00002530 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002531 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002532 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002533
Steve French630f3f02007-10-25 21:17:17 +00002534 *pdatalen = 0;
2535 *pparmlen = 0;
2536
Steve French790fe572007-07-07 19:25:05 +00002537 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002538 return -EINVAL;
2539
2540 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2541
2542 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002543 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002544 (char *)&pSMBr->ByteCount;
2545
Steve French0a4b92c2006-01-12 15:44:21 -08002546 data_offset = le32_to_cpu(pSMBr->DataOffset);
2547 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002548 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002549 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2550
2551 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2552 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2553
2554 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002555 if (*ppparm > end_of_smb) {
2556 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002557 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002558 } else if (parm_count + *ppparm > end_of_smb) {
2559 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002560 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002561 } else if (*ppdata > end_of_smb) {
2562 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002563 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002564 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002565 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002566 *ppdata, data_count, (data_count + *ppdata),
2567 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002568 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002569 } else if (parm_count + data_count > pSMBr->ByteCount) {
2570 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002571 return -EINVAL;
2572 }
Steve French630f3f02007-10-25 21:17:17 +00002573 *pdatalen = data_count;
2574 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002575 return 0;
2576}
Parag Warudkarc9489772007-10-23 18:09:48 +00002577#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002578
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579int
2580CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2581 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002582 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 const struct nls_table *nls_codepage)
2584{
2585 int rc = 0;
2586 int bytes_returned;
2587 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002588 struct smb_com_transaction_ioctl_req *pSMB;
2589 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
2591 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2592 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2593 (void **) &pSMBr);
2594 if (rc)
2595 return rc;
2596
2597 pSMB->TotalParameterCount = 0 ;
2598 pSMB->TotalDataCount = 0;
2599 pSMB->MaxParameterCount = cpu_to_le32(2);
2600 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002601 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2602 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 pSMB->MaxSetupCount = 4;
2604 pSMB->Reserved = 0;
2605 pSMB->ParameterOffset = 0;
2606 pSMB->DataCount = 0;
2607 pSMB->DataOffset = 0;
2608 pSMB->SetupCount = 4;
2609 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2610 pSMB->ParameterCount = pSMB->TotalParameterCount;
2611 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2612 pSMB->IsFsctl = 1; /* FSCTL */
2613 pSMB->IsRootFlag = 0;
2614 pSMB->Fid = fid; /* file handle always le */
2615 pSMB->ByteCount = 0;
2616
2617 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2618 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2619 if (rc) {
2620 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2621 } else { /* decode response */
2622 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2623 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2624 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2625 /* BB also check enough total bytes returned */
2626 rc = -EIO; /* bad smb */
2627 else {
Steve French790fe572007-07-07 19:25:05 +00002628 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002629 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002630 pSMBr->ByteCount +
2631 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
Steve French50c2f752007-07-13 00:33:32 +00002633 struct reparse_data *reparse_buf =
2634 (struct reparse_data *)
2635 ((char *)&pSMBr->hdr.Protocol
2636 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002637 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 rc = -EIO;
2639 goto qreparse_out;
2640 }
Steve French790fe572007-07-07 19:25:05 +00002641 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 reparse_buf->TargetNameOffset +
2643 reparse_buf->TargetNameLen) >
2644 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002645 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 rc = -EIO;
2647 goto qreparse_out;
2648 }
Steve French50c2f752007-07-13 00:33:32 +00002649
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2651 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002652 (reparse_buf->LinkNamesBuf +
2653 reparse_buf->TargetNameOffset),
2654 min(buflen/2,
2655 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002657 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 reparse_buf->TargetNameOffset),
2659 name_len, nls_codepage);
2660 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002661 strncpy(symlinkinfo,
2662 reparse_buf->LinkNamesBuf +
2663 reparse_buf->TargetNameOffset,
2664 min_t(const int, buflen,
2665 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 }
2667 } else {
2668 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002669 cFYI(1, ("Invalid return data count on "
2670 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 }
2672 symlinkinfo[buflen] = 0; /* just in case so the caller
2673 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002674 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 }
2676 }
2677qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002678 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679
2680 /* Note: On -EAGAIN error only caller can retry on handle based calls
2681 since file handle passed in no longer valid */
2682
2683 return rc;
2684}
2685
2686#ifdef CONFIG_CIFS_POSIX
2687
2688/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002689static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2690 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691{
2692 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002693 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2694 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2695 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2697
2698 return;
2699}
2700
2701/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002702static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2703 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704{
2705 int size = 0;
2706 int i;
2707 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002708 struct cifs_posix_ace *pACE;
2709 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2710 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
2712 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2713 return -EOPNOTSUPP;
2714
Steve French790fe572007-07-07 19:25:05 +00002715 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 count = le16_to_cpu(cifs_acl->access_entry_count);
2717 pACE = &cifs_acl->ace_array[0];
2718 size = sizeof(struct cifs_posix_acl);
2719 size += sizeof(struct cifs_posix_ace) * count;
2720 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002721 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002722 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2723 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 return -EINVAL;
2725 }
Steve French790fe572007-07-07 19:25:05 +00002726 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 count = le16_to_cpu(cifs_acl->access_entry_count);
2728 size = sizeof(struct cifs_posix_acl);
2729 size += sizeof(struct cifs_posix_ace) * count;
2730/* skip past access ACEs to get to default ACEs */
2731 pACE = &cifs_acl->ace_array[count];
2732 count = le16_to_cpu(cifs_acl->default_entry_count);
2733 size += sizeof(struct cifs_posix_ace) * count;
2734 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002735 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 return -EINVAL;
2737 } else {
2738 /* illegal type */
2739 return -EINVAL;
2740 }
2741
2742 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002743 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002744 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002745 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 return -ERANGE;
2747 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002748 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002749 for (i = 0; i < count ; i++) {
2750 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2751 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 }
2753 }
2754 return size;
2755}
2756
Steve French50c2f752007-07-13 00:33:32 +00002757static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2758 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759{
2760 __u16 rc = 0; /* 0 = ACL converted ok */
2761
Steve Frenchff7feac2005-11-15 16:45:16 -08002762 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2763 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002765 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 /* Probably no need to le convert -1 on any arch but can not hurt */
2767 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002768 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002769 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002770 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 return rc;
2772}
2773
2774/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002775static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2776 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777{
2778 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002779 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2780 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 int count;
2782 int i;
2783
Steve French790fe572007-07-07 19:25:05 +00002784 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 return 0;
2786
2787 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002788 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002789 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002790 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002791 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002792 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002793 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 return 0;
2795 }
2796 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002797 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002798 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002799 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002800 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 else {
Steve French50c2f752007-07-13 00:33:32 +00002802 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 return 0;
2804 }
Steve French50c2f752007-07-13 00:33:32 +00002805 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2807 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002808 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 /* ACE not converted */
2810 break;
2811 }
2812 }
Steve French790fe572007-07-07 19:25:05 +00002813 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2815 rc += sizeof(struct cifs_posix_acl);
2816 /* BB add check to make sure ACL does not overflow SMB */
2817 }
2818 return rc;
2819}
2820
2821int
2822CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002823 const unsigned char *searchName,
2824 char *acl_inf, const int buflen, const int acl_type,
2825 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826{
2827/* SMB_QUERY_POSIX_ACL */
2828 TRANSACTION2_QPI_REQ *pSMB = NULL;
2829 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2830 int rc = 0;
2831 int bytes_returned;
2832 int name_len;
2833 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002834
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2836
2837queryAclRetry:
2838 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2839 (void **) &pSMBr);
2840 if (rc)
2841 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002842
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2844 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002845 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002846 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 name_len++; /* trailing null */
2848 name_len *= 2;
2849 pSMB->FileName[name_len] = 0;
2850 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002851 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 name_len = strnlen(searchName, PATH_MAX);
2853 name_len++; /* trailing null */
2854 strncpy(pSMB->FileName, searchName, name_len);
2855 }
2856
2857 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2858 pSMB->TotalDataCount = 0;
2859 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002860 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 pSMB->MaxDataCount = cpu_to_le16(4000);
2862 pSMB->MaxSetupCount = 0;
2863 pSMB->Reserved = 0;
2864 pSMB->Flags = 0;
2865 pSMB->Timeout = 0;
2866 pSMB->Reserved2 = 0;
2867 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002868 offsetof(struct smb_com_transaction2_qpi_req,
2869 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 pSMB->DataCount = 0;
2871 pSMB->DataOffset = 0;
2872 pSMB->SetupCount = 1;
2873 pSMB->Reserved3 = 0;
2874 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2875 byte_count = params + 1 /* pad */ ;
2876 pSMB->TotalParameterCount = cpu_to_le16(params);
2877 pSMB->ParameterCount = pSMB->TotalParameterCount;
2878 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2879 pSMB->Reserved4 = 0;
2880 pSMB->hdr.smb_buf_length += byte_count;
2881 pSMB->ByteCount = cpu_to_le16(byte_count);
2882
2883 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2884 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002885 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 if (rc) {
2887 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2888 } else {
2889 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002890
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2892 if (rc || (pSMBr->ByteCount < 2))
2893 /* BB also check enough total bytes returned */
2894 rc = -EIO; /* bad smb */
2895 else {
2896 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2897 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2898 rc = cifs_copy_posix_acl(acl_inf,
2899 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002900 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 }
2902 }
2903 cifs_buf_release(pSMB);
2904 if (rc == -EAGAIN)
2905 goto queryAclRetry;
2906 return rc;
2907}
2908
2909int
2910CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002911 const unsigned char *fileName,
2912 const char *local_acl, const int buflen,
2913 const int acl_type,
2914 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915{
2916 struct smb_com_transaction2_spi_req *pSMB = NULL;
2917 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2918 char *parm_data;
2919 int name_len;
2920 int rc = 0;
2921 int bytes_returned = 0;
2922 __u16 params, byte_count, data_count, param_offset, offset;
2923
2924 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2925setAclRetry:
2926 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002927 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 if (rc)
2929 return rc;
2930 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2931 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002932 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002933 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 name_len++; /* trailing null */
2935 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002936 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 name_len = strnlen(fileName, PATH_MAX);
2938 name_len++; /* trailing null */
2939 strncpy(pSMB->FileName, fileName, name_len);
2940 }
2941 params = 6 + name_len;
2942 pSMB->MaxParameterCount = cpu_to_le16(2);
2943 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2944 pSMB->MaxSetupCount = 0;
2945 pSMB->Reserved = 0;
2946 pSMB->Flags = 0;
2947 pSMB->Timeout = 0;
2948 pSMB->Reserved2 = 0;
2949 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002950 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 offset = param_offset + params;
2952 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2953 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2954
2955 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002956 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957
Steve French790fe572007-07-07 19:25:05 +00002958 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 rc = -EOPNOTSUPP;
2960 goto setACLerrorExit;
2961 }
2962 pSMB->DataOffset = cpu_to_le16(offset);
2963 pSMB->SetupCount = 1;
2964 pSMB->Reserved3 = 0;
2965 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2966 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2967 byte_count = 3 /* pad */ + params + data_count;
2968 pSMB->DataCount = cpu_to_le16(data_count);
2969 pSMB->TotalDataCount = pSMB->DataCount;
2970 pSMB->ParameterCount = cpu_to_le16(params);
2971 pSMB->TotalParameterCount = pSMB->ParameterCount;
2972 pSMB->Reserved4 = 0;
2973 pSMB->hdr.smb_buf_length += byte_count;
2974 pSMB->ByteCount = cpu_to_le16(byte_count);
2975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 if (rc) {
2978 cFYI(1, ("Set POSIX ACL returned %d", rc));
2979 }
2980
2981setACLerrorExit:
2982 cifs_buf_release(pSMB);
2983 if (rc == -EAGAIN)
2984 goto setAclRetry;
2985 return rc;
2986}
2987
Steve Frenchf654bac2005-04-28 22:41:04 -07002988/* BB fix tabs in this function FIXME BB */
2989int
2990CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002991 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002992{
Steve French50c2f752007-07-13 00:33:32 +00002993 int rc = 0;
2994 struct smb_t2_qfi_req *pSMB = NULL;
2995 struct smb_t2_qfi_rsp *pSMBr = NULL;
2996 int bytes_returned;
2997 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002998
Steve French790fe572007-07-07 19:25:05 +00002999 cFYI(1, ("In GetExtAttr"));
3000 if (tcon == NULL)
3001 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003002
3003GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003004 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3005 (void **) &pSMBr);
3006 if (rc)
3007 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003008
Steve French790fe572007-07-07 19:25:05 +00003009 params = 2 /* level */ +2 /* fid */;
3010 pSMB->t2.TotalDataCount = 0;
3011 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3012 /* BB find exact max data count below from sess structure BB */
3013 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3014 pSMB->t2.MaxSetupCount = 0;
3015 pSMB->t2.Reserved = 0;
3016 pSMB->t2.Flags = 0;
3017 pSMB->t2.Timeout = 0;
3018 pSMB->t2.Reserved2 = 0;
3019 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3020 Fid) - 4);
3021 pSMB->t2.DataCount = 0;
3022 pSMB->t2.DataOffset = 0;
3023 pSMB->t2.SetupCount = 1;
3024 pSMB->t2.Reserved3 = 0;
3025 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3026 byte_count = params + 1 /* pad */ ;
3027 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3028 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3029 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3030 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003031 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003032 pSMB->hdr.smb_buf_length += byte_count;
3033 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003034
Steve French790fe572007-07-07 19:25:05 +00003035 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3036 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3037 if (rc) {
3038 cFYI(1, ("error %d in GetExtAttr", rc));
3039 } else {
3040 /* decode response */
3041 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3042 if (rc || (pSMBr->ByteCount < 2))
3043 /* BB also check enough total bytes returned */
3044 /* If rc should we check for EOPNOSUPP and
3045 disable the srvino flag? or in caller? */
3046 rc = -EIO; /* bad smb */
3047 else {
3048 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3049 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3050 struct file_chattr_info *pfinfo;
3051 /* BB Do we need a cast or hash here ? */
3052 if (count != 16) {
3053 cFYI(1, ("Illegal size ret in GetExtAttr"));
3054 rc = -EIO;
3055 goto GetExtAttrOut;
3056 }
3057 pfinfo = (struct file_chattr_info *)
3058 (data_offset + (char *) &pSMBr->hdr.Protocol);
3059 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003060 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003061 }
3062 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003063GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003064 cifs_buf_release(pSMB);
3065 if (rc == -EAGAIN)
3066 goto GetExtAttrRetry;
3067 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003068}
3069
Steve Frenchf654bac2005-04-28 22:41:04 -07003070#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071
Steve French297647c2007-10-12 04:11:59 +00003072#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003073/* Get Security Descriptor (by handle) from remote server for a file or dir */
3074int
3075CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003076 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003077{
3078 int rc = 0;
3079 int buf_type = 0;
3080 QUERY_SEC_DESC_REQ * pSMB;
3081 struct kvec iov[1];
3082
3083 cFYI(1, ("GetCifsACL"));
3084
Steve French630f3f02007-10-25 21:17:17 +00003085 *pbuflen = 0;
3086 *acl_inf = NULL;
3087
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003088 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003089 8 /* parm len */, tcon, (void **) &pSMB);
3090 if (rc)
3091 return rc;
3092
3093 pSMB->MaxParameterCount = cpu_to_le32(4);
3094 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3095 pSMB->MaxSetupCount = 0;
3096 pSMB->Fid = fid; /* file handle always le */
3097 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3098 CIFS_ACL_DACL);
3099 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3100 pSMB->hdr.smb_buf_length += 11;
3101 iov[0].iov_base = (char *)pSMB;
3102 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3103
Steve Frencha761ac52007-10-18 21:45:27 +00003104 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3105 0 /* not long op */, 0 /* do not log STATUS codes */ );
Steve French0a4b92c2006-01-12 15:44:21 -08003106 cifs_stats_inc(&tcon->num_acl_get);
3107 if (rc) {
3108 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3109 } else { /* decode response */
Steve French0a4b92c2006-01-12 15:44:21 -08003110 __le32 * parm;
Steve French630f3f02007-10-25 21:17:17 +00003111 __u32 parm_len;
3112 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003113 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003114 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003115
3116/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003117 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003118 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003119 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003120 goto qsec_out;
3121 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3122
Steve French630f3f02007-10-25 21:17:17 +00003123 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003124
3125 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3126 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003127 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003128 goto qsec_out;
3129 }
3130
3131/* BB check that data area is minimum length and as big as acl_len */
3132
Steve Frenchaf6f4612007-10-16 18:40:37 +00003133 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003134 if (acl_len != *pbuflen) {
3135 cERROR(1, ("acl length %d does not match %d",
3136 acl_len, *pbuflen));
3137 if (*pbuflen > acl_len)
3138 *pbuflen = acl_len;
3139 }
Steve French0a4b92c2006-01-12 15:44:21 -08003140
Steve French630f3f02007-10-25 21:17:17 +00003141 /* check if buffer is big enough for the acl
3142 header followed by the smallest SID */
3143 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3144 (*pbuflen >= 64 * 1024)) {
3145 cERROR(1, ("bad acl length %d", *pbuflen));
3146 rc = -EINVAL;
3147 *pbuflen = 0;
3148 } else {
3149 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3150 if (*acl_inf == NULL) {
3151 *pbuflen = 0;
3152 rc = -ENOMEM;
3153 }
3154 memcpy(*acl_inf, pdata, *pbuflen);
3155 }
Steve French0a4b92c2006-01-12 15:44:21 -08003156 }
3157qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003158 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003159 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003160 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003161 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003162/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003163 return rc;
3164}
Steve French297647c2007-10-12 04:11:59 +00003165#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003166
Steve French6b8edfe2005-08-23 20:26:03 -07003167/* Legacy Query Path Information call for lookup to old servers such
3168 as Win9x/WinME */
3169int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003170 const unsigned char *searchName,
3171 FILE_ALL_INFO *pFinfo,
3172 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003173{
3174 QUERY_INFORMATION_REQ * pSMB;
3175 QUERY_INFORMATION_RSP * pSMBr;
3176 int rc = 0;
3177 int bytes_returned;
3178 int name_len;
3179
Steve French50c2f752007-07-13 00:33:32 +00003180 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003181QInfRetry:
3182 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003183 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003184 if (rc)
3185 return rc;
3186
3187 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3188 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003189 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3190 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003191 name_len++; /* trailing null */
3192 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003193 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003194 name_len = strnlen(searchName, PATH_MAX);
3195 name_len++; /* trailing null */
3196 strncpy(pSMB->FileName, searchName, name_len);
3197 }
3198 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003199 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003200 pSMB->hdr.smb_buf_length += (__u16) name_len;
3201 pSMB->ByteCount = cpu_to_le16(name_len);
3202
3203 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003204 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003205 if (rc) {
3206 cFYI(1, ("Send error in QueryInfo = %d", rc));
3207 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003208 struct timespec ts;
3209 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3210 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003211 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003212 ts.tv_nsec = 0;
3213 ts.tv_sec = time;
3214 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003215 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003216 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3217 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003218 pFinfo->AllocationSize =
3219 cpu_to_le64(le32_to_cpu(pSMBr->size));
3220 pFinfo->EndOfFile = pFinfo->AllocationSize;
3221 pFinfo->Attributes =
3222 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003223 } else
3224 rc = -EIO; /* bad buffer passed in */
3225
3226 cifs_buf_release(pSMB);
3227
3228 if (rc == -EAGAIN)
3229 goto QInfRetry;
3230
3231 return rc;
3232}
3233
3234
3235
3236
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237int
3238CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3239 const unsigned char *searchName,
3240 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003241 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003242 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243{
3244/* level 263 SMB_QUERY_FILE_ALL_INFO */
3245 TRANSACTION2_QPI_REQ *pSMB = NULL;
3246 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3247 int rc = 0;
3248 int bytes_returned;
3249 int name_len;
3250 __u16 params, byte_count;
3251
3252/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3253QPathInfoRetry:
3254 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3255 (void **) &pSMBr);
3256 if (rc)
3257 return rc;
3258
3259 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3260 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003261 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003262 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 name_len++; /* trailing null */
3264 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003265 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 name_len = strnlen(searchName, PATH_MAX);
3267 name_len++; /* trailing null */
3268 strncpy(pSMB->FileName, searchName, name_len);
3269 }
3270
Steve French50c2f752007-07-13 00:33:32 +00003271 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 pSMB->TotalDataCount = 0;
3273 pSMB->MaxParameterCount = cpu_to_le16(2);
3274 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3275 pSMB->MaxSetupCount = 0;
3276 pSMB->Reserved = 0;
3277 pSMB->Flags = 0;
3278 pSMB->Timeout = 0;
3279 pSMB->Reserved2 = 0;
3280 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003281 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 pSMB->DataCount = 0;
3283 pSMB->DataOffset = 0;
3284 pSMB->SetupCount = 1;
3285 pSMB->Reserved3 = 0;
3286 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3287 byte_count = params + 1 /* pad */ ;
3288 pSMB->TotalParameterCount = cpu_to_le16(params);
3289 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003290 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003291 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3292 else
3293 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 pSMB->Reserved4 = 0;
3295 pSMB->hdr.smb_buf_length += byte_count;
3296 pSMB->ByteCount = cpu_to_le16(byte_count);
3297
3298 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3299 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3300 if (rc) {
3301 cFYI(1, ("Send error in QPathInfo = %d", rc));
3302 } else { /* decode response */
3303 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3304
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003305 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3306 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003307 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003309 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003310 rc = -EIO; /* 24 or 26 expected but we do not read
3311 last field */
3312 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003313 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003315 if (legacy) /* we do not read the last field, EAsize,
3316 fortunately since it varies by subdialect
3317 and on Set vs. Get, is two bytes or 4
3318 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003319 size = sizeof(FILE_INFO_STANDARD);
3320 else
3321 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 memcpy((char *) pFindData,
3323 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003324 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 } else
3326 rc = -ENOMEM;
3327 }
3328 cifs_buf_release(pSMB);
3329 if (rc == -EAGAIN)
3330 goto QPathInfoRetry;
3331
3332 return rc;
3333}
3334
3335int
3336CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3337 const unsigned char *searchName,
3338 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003339 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340{
3341/* SMB_QUERY_FILE_UNIX_BASIC */
3342 TRANSACTION2_QPI_REQ *pSMB = NULL;
3343 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3344 int rc = 0;
3345 int bytes_returned = 0;
3346 int name_len;
3347 __u16 params, byte_count;
3348
3349 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3350UnixQPathInfoRetry:
3351 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3352 (void **) &pSMBr);
3353 if (rc)
3354 return rc;
3355
3356 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3357 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003358 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003359 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 name_len++; /* trailing null */
3361 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003362 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 name_len = strnlen(searchName, PATH_MAX);
3364 name_len++; /* trailing null */
3365 strncpy(pSMB->FileName, searchName, name_len);
3366 }
3367
Steve French50c2f752007-07-13 00:33:32 +00003368 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 pSMB->TotalDataCount = 0;
3370 pSMB->MaxParameterCount = cpu_to_le16(2);
3371 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003372 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 pSMB->MaxSetupCount = 0;
3374 pSMB->Reserved = 0;
3375 pSMB->Flags = 0;
3376 pSMB->Timeout = 0;
3377 pSMB->Reserved2 = 0;
3378 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003379 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 pSMB->DataCount = 0;
3381 pSMB->DataOffset = 0;
3382 pSMB->SetupCount = 1;
3383 pSMB->Reserved3 = 0;
3384 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3385 byte_count = params + 1 /* pad */ ;
3386 pSMB->TotalParameterCount = cpu_to_le16(params);
3387 pSMB->ParameterCount = pSMB->TotalParameterCount;
3388 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3389 pSMB->Reserved4 = 0;
3390 pSMB->hdr.smb_buf_length += byte_count;
3391 pSMB->ByteCount = cpu_to_le16(byte_count);
3392
3393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3395 if (rc) {
3396 cFYI(1, ("Send error in QPathInfo = %d", rc));
3397 } else { /* decode response */
3398 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3399
3400 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003401 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3402 "Unix Extensions can be disabled on mount "
3403 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 rc = -EIO; /* bad smb */
3405 } else {
3406 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3407 memcpy((char *) pFindData,
3408 (char *) &pSMBr->hdr.Protocol +
3409 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003410 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 }
3412 }
3413 cifs_buf_release(pSMB);
3414 if (rc == -EAGAIN)
3415 goto UnixQPathInfoRetry;
3416
3417 return rc;
3418}
3419
3420#if 0 /* function unused at present */
3421int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3422 const char *searchName, FILE_ALL_INFO * findData,
3423 const struct nls_table *nls_codepage)
3424{
3425/* level 257 SMB_ */
3426 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3427 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3428 int rc = 0;
3429 int bytes_returned;
3430 int name_len;
3431 __u16 params, byte_count;
3432
3433 cFYI(1, ("In FindUnique"));
3434findUniqueRetry:
3435 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3436 (void **) &pSMBr);
3437 if (rc)
3438 return rc;
3439
3440 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3441 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003442 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3443 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 name_len++; /* trailing null */
3445 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003446 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 name_len = strnlen(searchName, PATH_MAX);
3448 name_len++; /* trailing null */
3449 strncpy(pSMB->FileName, searchName, name_len);
3450 }
3451
3452 params = 12 + name_len /* includes null */ ;
3453 pSMB->TotalDataCount = 0; /* no EAs */
3454 pSMB->MaxParameterCount = cpu_to_le16(2);
3455 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3456 pSMB->MaxSetupCount = 0;
3457 pSMB->Reserved = 0;
3458 pSMB->Flags = 0;
3459 pSMB->Timeout = 0;
3460 pSMB->Reserved2 = 0;
3461 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003462 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 pSMB->DataCount = 0;
3464 pSMB->DataOffset = 0;
3465 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3466 pSMB->Reserved3 = 0;
3467 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3468 byte_count = params + 1 /* pad */ ;
3469 pSMB->TotalParameterCount = cpu_to_le16(params);
3470 pSMB->ParameterCount = pSMB->TotalParameterCount;
3471 pSMB->SearchAttributes =
3472 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3473 ATTR_DIRECTORY);
3474 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3475 pSMB->SearchFlags = cpu_to_le16(1);
3476 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3477 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3478 pSMB->hdr.smb_buf_length += byte_count;
3479 pSMB->ByteCount = cpu_to_le16(byte_count);
3480
3481 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3482 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3483
3484 if (rc) {
3485 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3486 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003487 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 /* BB fill in */
3489 }
3490
3491 cifs_buf_release(pSMB);
3492 if (rc == -EAGAIN)
3493 goto findUniqueRetry;
3494
3495 return rc;
3496}
3497#endif /* end unused (temporarily) function */
3498
3499/* xid, tcon, searchName and codepage are input parms, rest are returned */
3500int
3501CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003502 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003504 __u16 *pnetfid,
3505 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506{
3507/* level 257 SMB_ */
3508 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3509 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3510 T2_FFIRST_RSP_PARMS * parms;
3511 int rc = 0;
3512 int bytes_returned = 0;
3513 int name_len;
3514 __u16 params, byte_count;
3515
Steve French50c2f752007-07-13 00:33:32 +00003516 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517
3518findFirstRetry:
3519 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3520 (void **) &pSMBr);
3521 if (rc)
3522 return rc;
3523
3524 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3525 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003526 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003527 PATH_MAX, nls_codepage, remap);
3528 /* We can not add the asterik earlier in case
3529 it got remapped to 0xF03A as if it were part of the
3530 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003532 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003533 pSMB->FileName[name_len+1] = 0;
3534 pSMB->FileName[name_len+2] = '*';
3535 pSMB->FileName[name_len+3] = 0;
3536 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3538 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003539 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 } else { /* BB add check for overrun of SMB buf BB */
3541 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003543 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 free buffer exit; BB */
3545 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003546 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003547 pSMB->FileName[name_len+1] = '*';
3548 pSMB->FileName[name_len+2] = 0;
3549 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 }
3551
3552 params = 12 + name_len /* includes null */ ;
3553 pSMB->TotalDataCount = 0; /* no EAs */
3554 pSMB->MaxParameterCount = cpu_to_le16(10);
3555 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3556 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3557 pSMB->MaxSetupCount = 0;
3558 pSMB->Reserved = 0;
3559 pSMB->Flags = 0;
3560 pSMB->Timeout = 0;
3561 pSMB->Reserved2 = 0;
3562 byte_count = params + 1 /* pad */ ;
3563 pSMB->TotalParameterCount = cpu_to_le16(params);
3564 pSMB->ParameterCount = pSMB->TotalParameterCount;
3565 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003566 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3567 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 pSMB->DataCount = 0;
3569 pSMB->DataOffset = 0;
3570 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3571 pSMB->Reserved3 = 0;
3572 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3573 pSMB->SearchAttributes =
3574 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3575 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003576 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3577 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 CIFS_SEARCH_RETURN_RESUME);
3579 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3580
3581 /* BB what should we set StorageType to? Does it matter? BB */
3582 pSMB->SearchStorageType = 0;
3583 pSMB->hdr.smb_buf_length += byte_count;
3584 pSMB->ByteCount = cpu_to_le16(byte_count);
3585
3586 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3587 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003588 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589
Steve French88274812006-03-09 22:21:45 +00003590 if (rc) {/* BB add logic to retry regular search if Unix search
3591 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 /* BB Add code to handle unsupported level rc */
3593 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003594
Steve French88274812006-03-09 22:21:45 +00003595 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597 /* BB eventually could optimize out free and realloc of buf */
3598 /* for this case */
3599 if (rc == -EAGAIN)
3600 goto findFirstRetry;
3601 } else { /* decode response */
3602 /* BB remember to free buffer if error BB */
3603 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003604 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3606 psrch_inf->unicode = TRUE;
3607 else
3608 psrch_inf->unicode = FALSE;
3609
3610 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003611 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003612 psrch_inf->srch_entries_start =
3613 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3616 le16_to_cpu(pSMBr->t2.ParameterOffset));
3617
Steve French790fe572007-07-07 19:25:05 +00003618 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 psrch_inf->endOfSearch = TRUE;
3620 else
3621 psrch_inf->endOfSearch = FALSE;
3622
Steve French50c2f752007-07-13 00:33:32 +00003623 psrch_inf->entries_in_buffer =
3624 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003625 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 *pnetfid = parms->SearchHandle;
3628 } else {
3629 cifs_buf_release(pSMB);
3630 }
3631 }
3632
3633 return rc;
3634}
3635
3636int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003637 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638{
3639 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3640 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3641 T2_FNEXT_RSP_PARMS * parms;
3642 char *response_data;
3643 int rc = 0;
3644 int bytes_returned, name_len;
3645 __u16 params, byte_count;
3646
3647 cFYI(1, ("In FindNext"));
3648
Steve French790fe572007-07-07 19:25:05 +00003649 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 return -ENOENT;
3651
3652 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3653 (void **) &pSMBr);
3654 if (rc)
3655 return rc;
3656
Steve French50c2f752007-07-13 00:33:32 +00003657 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 byte_count = 0;
3659 pSMB->TotalDataCount = 0; /* no EAs */
3660 pSMB->MaxParameterCount = cpu_to_le16(8);
3661 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003662 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3663 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 pSMB->MaxSetupCount = 0;
3665 pSMB->Reserved = 0;
3666 pSMB->Flags = 0;
3667 pSMB->Timeout = 0;
3668 pSMB->Reserved2 = 0;
3669 pSMB->ParameterOffset = cpu_to_le16(
3670 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3671 pSMB->DataCount = 0;
3672 pSMB->DataOffset = 0;
3673 pSMB->SetupCount = 1;
3674 pSMB->Reserved3 = 0;
3675 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3676 pSMB->SearchHandle = searchHandle; /* always kept as le */
3677 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003678 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3680 pSMB->ResumeKey = psrch_inf->resume_key;
3681 pSMB->SearchFlags =
3682 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3683
3684 name_len = psrch_inf->resume_name_len;
3685 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003686 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3688 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003689 /* 14 byte parm len above enough for 2 byte null terminator */
3690 pSMB->ResumeFileName[name_len] = 0;
3691 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 } else {
3693 rc = -EINVAL;
3694 goto FNext2_err_exit;
3695 }
3696 byte_count = params + 1 /* pad */ ;
3697 pSMB->TotalParameterCount = cpu_to_le16(params);
3698 pSMB->ParameterCount = pSMB->TotalParameterCount;
3699 pSMB->hdr.smb_buf_length += byte_count;
3700 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003701
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3703 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003704 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 if (rc) {
3706 if (rc == -EBADF) {
3707 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003708 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 } else
3710 cFYI(1, ("FindNext returned = %d", rc));
3711 } else { /* decode response */
3712 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003713
Steve French790fe572007-07-07 19:25:05 +00003714 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 /* BB fixme add lock for file (srch_info) struct here */
3716 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3717 psrch_inf->unicode = TRUE;
3718 else
3719 psrch_inf->unicode = FALSE;
3720 response_data = (char *) &pSMBr->hdr.Protocol +
3721 le16_to_cpu(pSMBr->t2.ParameterOffset);
3722 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3723 response_data = (char *)&pSMBr->hdr.Protocol +
3724 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003725 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003726 cifs_small_buf_release(
3727 psrch_inf->ntwrk_buf_start);
3728 else
3729 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 psrch_inf->srch_entries_start = response_data;
3731 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003732 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003733 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 psrch_inf->endOfSearch = TRUE;
3735 else
3736 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003737 psrch_inf->entries_in_buffer =
3738 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 psrch_inf->index_of_last_entry +=
3740 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003741/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3742 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743
3744 /* BB fixme add unlock here */
3745 }
3746
3747 }
3748
3749 /* BB On error, should we leave previous search buf (and count and
3750 last entry fields) intact or free the previous one? */
3751
3752 /* Note: On -EAGAIN error only caller can retry on handle based calls
3753 since file handle passed in no longer valid */
3754FNext2_err_exit:
3755 if (rc != 0)
3756 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 return rc;
3758}
3759
3760int
Steve French50c2f752007-07-13 00:33:32 +00003761CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3762 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763{
3764 int rc = 0;
3765 FINDCLOSE_REQ *pSMB = NULL;
3766 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3767 int bytes_returned;
3768
3769 cFYI(1, ("In CIFSSMBFindClose"));
3770 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3771
3772 /* no sense returning error if session restarted
3773 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003774 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 return 0;
3776 if (rc)
3777 return rc;
3778
3779 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3780 pSMB->FileID = searchHandle;
3781 pSMB->ByteCount = 0;
3782 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3783 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3784 if (rc) {
3785 cERROR(1, ("Send error in FindClose = %d", rc));
3786 }
Steve Frencha4544342005-08-24 13:59:35 -07003787 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 cifs_small_buf_release(pSMB);
3789
3790 /* Since session is dead, search handle closed on server already */
3791 if (rc == -EAGAIN)
3792 rc = 0;
3793
3794 return rc;
3795}
3796
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797int
3798CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003799 const unsigned char *searchName,
3800 __u64 * inode_number,
3801 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802{
3803 int rc = 0;
3804 TRANSACTION2_QPI_REQ *pSMB = NULL;
3805 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3806 int name_len, bytes_returned;
3807 __u16 params, byte_count;
3808
Steve French50c2f752007-07-13 00:33:32 +00003809 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003810 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003811 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812
3813GetInodeNumberRetry:
3814 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003815 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 if (rc)
3817 return rc;
3818
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3820 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003821 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003822 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 name_len++; /* trailing null */
3824 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003825 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 name_len = strnlen(searchName, PATH_MAX);
3827 name_len++; /* trailing null */
3828 strncpy(pSMB->FileName, searchName, name_len);
3829 }
3830
3831 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3832 pSMB->TotalDataCount = 0;
3833 pSMB->MaxParameterCount = cpu_to_le16(2);
3834 /* BB find exact max data count below from sess structure BB */
3835 pSMB->MaxDataCount = cpu_to_le16(4000);
3836 pSMB->MaxSetupCount = 0;
3837 pSMB->Reserved = 0;
3838 pSMB->Flags = 0;
3839 pSMB->Timeout = 0;
3840 pSMB->Reserved2 = 0;
3841 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003842 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 pSMB->DataCount = 0;
3844 pSMB->DataOffset = 0;
3845 pSMB->SetupCount = 1;
3846 pSMB->Reserved3 = 0;
3847 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3848 byte_count = params + 1 /* pad */ ;
3849 pSMB->TotalParameterCount = cpu_to_le16(params);
3850 pSMB->ParameterCount = pSMB->TotalParameterCount;
3851 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3852 pSMB->Reserved4 = 0;
3853 pSMB->hdr.smb_buf_length += byte_count;
3854 pSMB->ByteCount = cpu_to_le16(byte_count);
3855
3856 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3857 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3858 if (rc) {
3859 cFYI(1, ("error %d in QueryInternalInfo", rc));
3860 } else {
3861 /* decode response */
3862 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3863 if (rc || (pSMBr->ByteCount < 2))
3864 /* BB also check enough total bytes returned */
3865 /* If rc should we check for EOPNOSUPP and
3866 disable the srvino flag? or in caller? */
3867 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003868 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3870 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003871 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003873 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3875 rc = -EIO;
3876 goto GetInodeNumOut;
3877 }
3878 pfinfo = (struct file_internal_info *)
3879 (data_offset + (char *) &pSMBr->hdr.Protocol);
3880 *inode_number = pfinfo->UniqueId;
3881 }
3882 }
3883GetInodeNumOut:
3884 cifs_buf_release(pSMB);
3885 if (rc == -EAGAIN)
3886 goto GetInodeNumberRetry;
3887 return rc;
3888}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889
3890int
3891CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3892 const unsigned char *searchName,
3893 unsigned char **targetUNCs,
3894 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003895 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896{
3897/* TRANS2_GET_DFS_REFERRAL */
3898 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3899 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003900 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 int rc = 0;
3902 int bytes_returned;
3903 int name_len;
3904 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003905 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 __u16 params, byte_count;
3907 *number_of_UNC_in_array = 0;
3908 *targetUNCs = NULL;
3909
3910 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3911 if (ses == NULL)
3912 return -ENODEV;
3913getDFSRetry:
3914 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3915 (void **) &pSMBr);
3916 if (rc)
3917 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003918
3919 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003920 but should never be null here anyway */
3921 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 pSMB->hdr.Tid = ses->ipc_tid;
3923 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003924 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003926 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928
3929 if (ses->capabilities & CAP_UNICODE) {
3930 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3931 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003932 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003933 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 name_len++; /* trailing null */
3935 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003936 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 name_len = strnlen(searchName, PATH_MAX);
3938 name_len++; /* trailing null */
3939 strncpy(pSMB->RequestFileName, searchName, name_len);
3940 }
3941
Steve French790fe572007-07-07 19:25:05 +00003942 if (ses->server) {
3943 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003944 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3945 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3946 }
3947
Steve French50c2f752007-07-13 00:33:32 +00003948 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003949
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 params = 2 /* level */ + name_len /*includes null */ ;
3951 pSMB->TotalDataCount = 0;
3952 pSMB->DataCount = 0;
3953 pSMB->DataOffset = 0;
3954 pSMB->MaxParameterCount = 0;
3955 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3956 pSMB->MaxSetupCount = 0;
3957 pSMB->Reserved = 0;
3958 pSMB->Flags = 0;
3959 pSMB->Timeout = 0;
3960 pSMB->Reserved2 = 0;
3961 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003962 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 pSMB->SetupCount = 1;
3964 pSMB->Reserved3 = 0;
3965 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3966 byte_count = params + 3 /* pad */ ;
3967 pSMB->ParameterCount = cpu_to_le16(params);
3968 pSMB->TotalParameterCount = pSMB->ParameterCount;
3969 pSMB->MaxReferralLevel = cpu_to_le16(3);
3970 pSMB->hdr.smb_buf_length += byte_count;
3971 pSMB->ByteCount = cpu_to_le16(byte_count);
3972
3973 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3975 if (rc) {
3976 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3977 } else { /* decode response */
3978/* BB Add logic to parse referrals here */
3979 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3980
Steve French50c2f752007-07-13 00:33:32 +00003981 /* BB Also check if enough total bytes returned? */
3982 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 rc = -EIO; /* bad smb */
3984 else {
Steve French50c2f752007-07-13 00:33:32 +00003985 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3987
3988 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003989 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003991 referrals =
3992 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 (8 /* sizeof start of data block */ +
3994 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003995 (char *) &pSMBr->hdr.Protocol);
Steve Frenchc18c8422007-07-18 23:21:09 +00003996 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
Steve French63135e02007-07-17 17:34:02 +00003997 "for referral one refer size: 0x%x srv "
3998 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00003999 le16_to_cpu(pSMBr->NumberOfReferrals),
4000 le16_to_cpu(pSMBr->DFSFlags),
4001 le16_to_cpu(referrals->ReferralSize),
4002 le16_to_cpu(referrals->ServerType),
4003 le16_to_cpu(referrals->ReferralFlags),
4004 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 /* BB This field is actually two bytes in from start of
4006 data block so we could do safety check that DataBlock
4007 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00004008 *number_of_UNC_in_array =
4009 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010
4011 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00004012 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 *number_of_UNC_in_array = 1;
4014
4015 /* get the length of the strings describing refs */
4016 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00004017 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00004019 __u16 offset =
4020 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00004022 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 not try to copy any more */
4024 *number_of_UNC_in_array = i;
4025 break;
Steve French50c2f752007-07-13 00:33:32 +00004026 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 temp = ((char *)referrals) + offset;
4028
4029 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00004030 name_len += UniStrnlen((wchar_t *)temp,
4031 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 } else {
Steve French50c2f752007-07-13 00:33:32 +00004033 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 }
4035 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004036 /* BB add check that referral pointer does
4037 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 }
4039 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004040 *targetUNCs =
4041 kmalloc(name_len+1+(*number_of_UNC_in_array),
4042 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004043 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 rc = -ENOMEM;
4045 goto GetDFSRefExit;
4046 }
4047 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004048 referrals = (struct dfs_referral_level_3 *)
4049 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 (char *) &pSMBr->hdr.Protocol);
4051
Steve French50c2f752007-07-13 00:33:32 +00004052 for (i = 0; i < *number_of_UNC_in_array; i++) {
4053 temp = ((char *)referrals) +
4054 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4056 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004057 (__le16 *) temp,
4058 name_len,
4059 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 } else {
Steve French50c2f752007-07-13 00:33:32 +00004061 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 }
4063 /* BB update target_uncs pointers */
4064 referrals++;
4065 }
4066 temp = *targetUNCs;
4067 temp[name_len] = 0;
4068 }
4069
4070 }
4071GetDFSRefExit:
4072 if (pSMB)
4073 cifs_buf_release(pSMB);
4074
4075 if (rc == -EAGAIN)
4076 goto getDFSRetry;
4077
4078 return rc;
4079}
4080
Steve French20962432005-09-21 22:05:57 -07004081/* Query File System Info such as free space to old servers such as Win 9x */
4082int
4083SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4084{
4085/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4086 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4087 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4088 FILE_SYSTEM_ALLOC_INFO *response_data;
4089 int rc = 0;
4090 int bytes_returned = 0;
4091 __u16 params, byte_count;
4092
4093 cFYI(1, ("OldQFSInfo"));
4094oldQFSInfoRetry:
4095 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4096 (void **) &pSMBr);
4097 if (rc)
4098 return rc;
Steve French20962432005-09-21 22:05:57 -07004099
4100 params = 2; /* level */
4101 pSMB->TotalDataCount = 0;
4102 pSMB->MaxParameterCount = cpu_to_le16(2);
4103 pSMB->MaxDataCount = cpu_to_le16(1000);
4104 pSMB->MaxSetupCount = 0;
4105 pSMB->Reserved = 0;
4106 pSMB->Flags = 0;
4107 pSMB->Timeout = 0;
4108 pSMB->Reserved2 = 0;
4109 byte_count = params + 1 /* pad */ ;
4110 pSMB->TotalParameterCount = cpu_to_le16(params);
4111 pSMB->ParameterCount = pSMB->TotalParameterCount;
4112 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4113 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4114 pSMB->DataCount = 0;
4115 pSMB->DataOffset = 0;
4116 pSMB->SetupCount = 1;
4117 pSMB->Reserved3 = 0;
4118 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4119 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4120 pSMB->hdr.smb_buf_length += byte_count;
4121 pSMB->ByteCount = cpu_to_le16(byte_count);
4122
4123 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4124 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4125 if (rc) {
4126 cFYI(1, ("Send error in QFSInfo = %d", rc));
4127 } else { /* decode response */
4128 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4129
4130 if (rc || (pSMBr->ByteCount < 18))
4131 rc = -EIO; /* bad smb */
4132 else {
4133 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004134 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004135 pSMBr->ByteCount, data_offset));
4136
Steve French50c2f752007-07-13 00:33:32 +00004137 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004138 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4139 FSData->f_bsize =
4140 le16_to_cpu(response_data->BytesPerSector) *
4141 le32_to_cpu(response_data->
4142 SectorsPerAllocationUnit);
4143 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004144 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004145 FSData->f_bfree = FSData->f_bavail =
4146 le32_to_cpu(response_data->FreeAllocationUnits);
4147 cFYI(1,
4148 ("Blocks: %lld Free: %lld Block size %ld",
4149 (unsigned long long)FSData->f_blocks,
4150 (unsigned long long)FSData->f_bfree,
4151 FSData->f_bsize));
4152 }
4153 }
4154 cifs_buf_release(pSMB);
4155
4156 if (rc == -EAGAIN)
4157 goto oldQFSInfoRetry;
4158
4159 return rc;
4160}
4161
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162int
Steve French737b7582005-04-28 22:41:06 -07004163CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164{
4165/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4166 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4167 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4168 FILE_SYSTEM_INFO *response_data;
4169 int rc = 0;
4170 int bytes_returned = 0;
4171 __u16 params, byte_count;
4172
4173 cFYI(1, ("In QFSInfo"));
4174QFSInfoRetry:
4175 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4176 (void **) &pSMBr);
4177 if (rc)
4178 return rc;
4179
4180 params = 2; /* level */
4181 pSMB->TotalDataCount = 0;
4182 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004183 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 pSMB->MaxSetupCount = 0;
4185 pSMB->Reserved = 0;
4186 pSMB->Flags = 0;
4187 pSMB->Timeout = 0;
4188 pSMB->Reserved2 = 0;
4189 byte_count = params + 1 /* pad */ ;
4190 pSMB->TotalParameterCount = cpu_to_le16(params);
4191 pSMB->ParameterCount = pSMB->TotalParameterCount;
4192 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004193 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 pSMB->DataCount = 0;
4195 pSMB->DataOffset = 0;
4196 pSMB->SetupCount = 1;
4197 pSMB->Reserved3 = 0;
4198 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4199 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4200 pSMB->hdr.smb_buf_length += byte_count;
4201 pSMB->ByteCount = cpu_to_le16(byte_count);
4202
4203 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4204 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4205 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004206 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004208 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209
Steve French20962432005-09-21 22:05:57 -07004210 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 rc = -EIO; /* bad smb */
4212 else {
4213 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214
4215 response_data =
4216 (FILE_SYSTEM_INFO
4217 *) (((char *) &pSMBr->hdr.Protocol) +
4218 data_offset);
4219 FSData->f_bsize =
4220 le32_to_cpu(response_data->BytesPerSector) *
4221 le32_to_cpu(response_data->
4222 SectorsPerAllocationUnit);
4223 FSData->f_blocks =
4224 le64_to_cpu(response_data->TotalAllocationUnits);
4225 FSData->f_bfree = FSData->f_bavail =
4226 le64_to_cpu(response_data->FreeAllocationUnits);
4227 cFYI(1,
4228 ("Blocks: %lld Free: %lld Block size %ld",
4229 (unsigned long long)FSData->f_blocks,
4230 (unsigned long long)FSData->f_bfree,
4231 FSData->f_bsize));
4232 }
4233 }
4234 cifs_buf_release(pSMB);
4235
4236 if (rc == -EAGAIN)
4237 goto QFSInfoRetry;
4238
4239 return rc;
4240}
4241
4242int
Steve French737b7582005-04-28 22:41:06 -07004243CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244{
4245/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4246 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4247 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4248 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4249 int rc = 0;
4250 int bytes_returned = 0;
4251 __u16 params, byte_count;
4252
4253 cFYI(1, ("In QFSAttributeInfo"));
4254QFSAttributeRetry:
4255 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4256 (void **) &pSMBr);
4257 if (rc)
4258 return rc;
4259
4260 params = 2; /* level */
4261 pSMB->TotalDataCount = 0;
4262 pSMB->MaxParameterCount = cpu_to_le16(2);
4263 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4264 pSMB->MaxSetupCount = 0;
4265 pSMB->Reserved = 0;
4266 pSMB->Flags = 0;
4267 pSMB->Timeout = 0;
4268 pSMB->Reserved2 = 0;
4269 byte_count = params + 1 /* pad */ ;
4270 pSMB->TotalParameterCount = cpu_to_le16(params);
4271 pSMB->ParameterCount = pSMB->TotalParameterCount;
4272 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004273 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 pSMB->DataCount = 0;
4275 pSMB->DataOffset = 0;
4276 pSMB->SetupCount = 1;
4277 pSMB->Reserved3 = 0;
4278 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4279 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4280 pSMB->hdr.smb_buf_length += byte_count;
4281 pSMB->ByteCount = cpu_to_le16(byte_count);
4282
4283 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4284 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4285 if (rc) {
4286 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4287 } else { /* decode response */
4288 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4289
Steve French50c2f752007-07-13 00:33:32 +00004290 if (rc || (pSMBr->ByteCount < 13)) {
4291 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 rc = -EIO; /* bad smb */
4293 } else {
4294 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4295 response_data =
4296 (FILE_SYSTEM_ATTRIBUTE_INFO
4297 *) (((char *) &pSMBr->hdr.Protocol) +
4298 data_offset);
4299 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004300 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 }
4302 }
4303 cifs_buf_release(pSMB);
4304
4305 if (rc == -EAGAIN)
4306 goto QFSAttributeRetry;
4307
4308 return rc;
4309}
4310
4311int
Steve French737b7582005-04-28 22:41:06 -07004312CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313{
4314/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4315 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4316 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4317 FILE_SYSTEM_DEVICE_INFO *response_data;
4318 int rc = 0;
4319 int bytes_returned = 0;
4320 __u16 params, byte_count;
4321
4322 cFYI(1, ("In QFSDeviceInfo"));
4323QFSDeviceRetry:
4324 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4325 (void **) &pSMBr);
4326 if (rc)
4327 return rc;
4328
4329 params = 2; /* level */
4330 pSMB->TotalDataCount = 0;
4331 pSMB->MaxParameterCount = cpu_to_le16(2);
4332 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4333 pSMB->MaxSetupCount = 0;
4334 pSMB->Reserved = 0;
4335 pSMB->Flags = 0;
4336 pSMB->Timeout = 0;
4337 pSMB->Reserved2 = 0;
4338 byte_count = params + 1 /* pad */ ;
4339 pSMB->TotalParameterCount = cpu_to_le16(params);
4340 pSMB->ParameterCount = pSMB->TotalParameterCount;
4341 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004342 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343
4344 pSMB->DataCount = 0;
4345 pSMB->DataOffset = 0;
4346 pSMB->SetupCount = 1;
4347 pSMB->Reserved3 = 0;
4348 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4349 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4350 pSMB->hdr.smb_buf_length += byte_count;
4351 pSMB->ByteCount = cpu_to_le16(byte_count);
4352
4353 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4354 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4355 if (rc) {
4356 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4357 } else { /* decode response */
4358 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4359
Steve French630f3f02007-10-25 21:17:17 +00004360 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 rc = -EIO; /* bad smb */
4362 else {
4363 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4364 response_data =
Steve French737b7582005-04-28 22:41:06 -07004365 (FILE_SYSTEM_DEVICE_INFO *)
4366 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 data_offset);
4368 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004369 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 }
4371 }
4372 cifs_buf_release(pSMB);
4373
4374 if (rc == -EAGAIN)
4375 goto QFSDeviceRetry;
4376
4377 return rc;
4378}
4379
4380int
Steve French737b7582005-04-28 22:41:06 -07004381CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382{
4383/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4384 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4385 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4386 FILE_SYSTEM_UNIX_INFO *response_data;
4387 int rc = 0;
4388 int bytes_returned = 0;
4389 __u16 params, byte_count;
4390
4391 cFYI(1, ("In QFSUnixInfo"));
4392QFSUnixRetry:
4393 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4394 (void **) &pSMBr);
4395 if (rc)
4396 return rc;
4397
4398 params = 2; /* level */
4399 pSMB->TotalDataCount = 0;
4400 pSMB->DataCount = 0;
4401 pSMB->DataOffset = 0;
4402 pSMB->MaxParameterCount = cpu_to_le16(2);
4403 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4404 pSMB->MaxSetupCount = 0;
4405 pSMB->Reserved = 0;
4406 pSMB->Flags = 0;
4407 pSMB->Timeout = 0;
4408 pSMB->Reserved2 = 0;
4409 byte_count = params + 1 /* pad */ ;
4410 pSMB->ParameterCount = cpu_to_le16(params);
4411 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004412 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4413 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 pSMB->SetupCount = 1;
4415 pSMB->Reserved3 = 0;
4416 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4417 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4418 pSMB->hdr.smb_buf_length += byte_count;
4419 pSMB->ByteCount = cpu_to_le16(byte_count);
4420
4421 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4422 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4423 if (rc) {
4424 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4425 } else { /* decode response */
4426 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4427
4428 if (rc || (pSMBr->ByteCount < 13)) {
4429 rc = -EIO; /* bad smb */
4430 } else {
4431 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4432 response_data =
4433 (FILE_SYSTEM_UNIX_INFO
4434 *) (((char *) &pSMBr->hdr.Protocol) +
4435 data_offset);
4436 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004437 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 }
4439 }
4440 cifs_buf_release(pSMB);
4441
4442 if (rc == -EAGAIN)
4443 goto QFSUnixRetry;
4444
4445
4446 return rc;
4447}
4448
Jeremy Allisonac670552005-06-22 17:26:35 -07004449int
Steve French45abc6e2005-06-23 13:42:03 -05004450CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004451{
4452/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4453 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4454 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4455 int rc = 0;
4456 int bytes_returned = 0;
4457 __u16 params, param_offset, offset, byte_count;
4458
4459 cFYI(1, ("In SETFSUnixInfo"));
4460SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004461 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004462 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4463 (void **) &pSMBr);
4464 if (rc)
4465 return rc;
4466
4467 params = 4; /* 2 bytes zero followed by info level. */
4468 pSMB->MaxSetupCount = 0;
4469 pSMB->Reserved = 0;
4470 pSMB->Flags = 0;
4471 pSMB->Timeout = 0;
4472 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004473 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4474 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004475 offset = param_offset + params;
4476
4477 pSMB->MaxParameterCount = cpu_to_le16(4);
4478 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4479 pSMB->SetupCount = 1;
4480 pSMB->Reserved3 = 0;
4481 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4482 byte_count = 1 /* pad */ + params + 12;
4483
4484 pSMB->DataCount = cpu_to_le16(12);
4485 pSMB->ParameterCount = cpu_to_le16(params);
4486 pSMB->TotalDataCount = pSMB->DataCount;
4487 pSMB->TotalParameterCount = pSMB->ParameterCount;
4488 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4489 pSMB->DataOffset = cpu_to_le16(offset);
4490
4491 /* Params. */
4492 pSMB->FileNum = 0;
4493 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4494
4495 /* Data. */
4496 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4497 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4498 pSMB->ClientUnixCap = cpu_to_le64(cap);
4499
4500 pSMB->hdr.smb_buf_length += byte_count;
4501 pSMB->ByteCount = cpu_to_le16(byte_count);
4502
4503 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4504 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4505 if (rc) {
4506 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4507 } else { /* decode response */
4508 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4509 if (rc) {
4510 rc = -EIO; /* bad smb */
4511 }
4512 }
4513 cifs_buf_release(pSMB);
4514
4515 if (rc == -EAGAIN)
4516 goto SETFSUnixRetry;
4517
4518 return rc;
4519}
4520
4521
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522
4523int
4524CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004525 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526{
4527/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4528 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4529 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4530 FILE_SYSTEM_POSIX_INFO *response_data;
4531 int rc = 0;
4532 int bytes_returned = 0;
4533 __u16 params, byte_count;
4534
4535 cFYI(1, ("In QFSPosixInfo"));
4536QFSPosixRetry:
4537 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4538 (void **) &pSMBr);
4539 if (rc)
4540 return rc;
4541
4542 params = 2; /* level */
4543 pSMB->TotalDataCount = 0;
4544 pSMB->DataCount = 0;
4545 pSMB->DataOffset = 0;
4546 pSMB->MaxParameterCount = cpu_to_le16(2);
4547 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4548 pSMB->MaxSetupCount = 0;
4549 pSMB->Reserved = 0;
4550 pSMB->Flags = 0;
4551 pSMB->Timeout = 0;
4552 pSMB->Reserved2 = 0;
4553 byte_count = params + 1 /* pad */ ;
4554 pSMB->ParameterCount = cpu_to_le16(params);
4555 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004556 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4557 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 pSMB->SetupCount = 1;
4559 pSMB->Reserved3 = 0;
4560 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4561 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4562 pSMB->hdr.smb_buf_length += byte_count;
4563 pSMB->ByteCount = cpu_to_le16(byte_count);
4564
4565 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4566 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4567 if (rc) {
4568 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4569 } else { /* decode response */
4570 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4571
4572 if (rc || (pSMBr->ByteCount < 13)) {
4573 rc = -EIO; /* bad smb */
4574 } else {
4575 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4576 response_data =
4577 (FILE_SYSTEM_POSIX_INFO
4578 *) (((char *) &pSMBr->hdr.Protocol) +
4579 data_offset);
4580 FSData->f_bsize =
4581 le32_to_cpu(response_data->BlockSize);
4582 FSData->f_blocks =
4583 le64_to_cpu(response_data->TotalBlocks);
4584 FSData->f_bfree =
4585 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004586 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587 FSData->f_bavail = FSData->f_bfree;
4588 } else {
4589 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004590 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 }
Steve French790fe572007-07-07 19:25:05 +00004592 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004594 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004595 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004597 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 }
4599 }
4600 cifs_buf_release(pSMB);
4601
4602 if (rc == -EAGAIN)
4603 goto QFSPosixRetry;
4604
4605 return rc;
4606}
4607
4608
Steve French50c2f752007-07-13 00:33:32 +00004609/* We can not use write of zero bytes trick to
4610 set file size due to need for large file support. Also note that
4611 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 routine which is only needed to work around a sharing violation bug
4613 in Samba which this routine can run into */
4614
4615int
4616CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004617 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004618 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619{
4620 struct smb_com_transaction2_spi_req *pSMB = NULL;
4621 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4622 struct file_end_of_file_info *parm_data;
4623 int name_len;
4624 int rc = 0;
4625 int bytes_returned = 0;
4626 __u16 params, byte_count, data_count, param_offset, offset;
4627
4628 cFYI(1, ("In SetEOF"));
4629SetEOFRetry:
4630 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4631 (void **) &pSMBr);
4632 if (rc)
4633 return rc;
4634
4635 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4636 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004637 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004638 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 name_len++; /* trailing null */
4640 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004641 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 name_len = strnlen(fileName, PATH_MAX);
4643 name_len++; /* trailing null */
4644 strncpy(pSMB->FileName, fileName, name_len);
4645 }
4646 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004647 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004649 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 pSMB->MaxSetupCount = 0;
4651 pSMB->Reserved = 0;
4652 pSMB->Flags = 0;
4653 pSMB->Timeout = 0;
4654 pSMB->Reserved2 = 0;
4655 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004656 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004658 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004659 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4660 pSMB->InformationLevel =
4661 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4662 else
4663 pSMB->InformationLevel =
4664 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4665 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4667 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004668 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 else
4670 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004671 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 }
4673
4674 parm_data =
4675 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4676 offset);
4677 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4678 pSMB->DataOffset = cpu_to_le16(offset);
4679 pSMB->SetupCount = 1;
4680 pSMB->Reserved3 = 0;
4681 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4682 byte_count = 3 /* pad */ + params + data_count;
4683 pSMB->DataCount = cpu_to_le16(data_count);
4684 pSMB->TotalDataCount = pSMB->DataCount;
4685 pSMB->ParameterCount = cpu_to_le16(params);
4686 pSMB->TotalParameterCount = pSMB->ParameterCount;
4687 pSMB->Reserved4 = 0;
4688 pSMB->hdr.smb_buf_length += byte_count;
4689 parm_data->FileSize = cpu_to_le64(size);
4690 pSMB->ByteCount = cpu_to_le16(byte_count);
4691 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4692 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4693 if (rc) {
4694 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4695 }
4696
4697 cifs_buf_release(pSMB);
4698
4699 if (rc == -EAGAIN)
4700 goto SetEOFRetry;
4701
4702 return rc;
4703}
4704
4705int
Steve French50c2f752007-07-13 00:33:32 +00004706CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4707 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708{
4709 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4710 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4711 char *data_offset;
4712 struct file_end_of_file_info *parm_data;
4713 int rc = 0;
4714 int bytes_returned = 0;
4715 __u16 params, param_offset, offset, byte_count, count;
4716
4717 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4718 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004719 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4720
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 if (rc)
4722 return rc;
4723
Steve Frenchcd634992005-04-28 22:41:10 -07004724 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4725
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4727 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004728
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 params = 6;
4730 pSMB->MaxSetupCount = 0;
4731 pSMB->Reserved = 0;
4732 pSMB->Flags = 0;
4733 pSMB->Timeout = 0;
4734 pSMB->Reserved2 = 0;
4735 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4736 offset = param_offset + params;
4737
Steve French50c2f752007-07-13 00:33:32 +00004738 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739
4740 count = sizeof(struct file_end_of_file_info);
4741 pSMB->MaxParameterCount = cpu_to_le16(2);
4742 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4743 pSMB->SetupCount = 1;
4744 pSMB->Reserved3 = 0;
4745 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4746 byte_count = 3 /* pad */ + params + count;
4747 pSMB->DataCount = cpu_to_le16(count);
4748 pSMB->ParameterCount = cpu_to_le16(params);
4749 pSMB->TotalDataCount = pSMB->DataCount;
4750 pSMB->TotalParameterCount = pSMB->ParameterCount;
4751 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4752 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004753 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4754 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 pSMB->DataOffset = cpu_to_le16(offset);
4756 parm_data->FileSize = cpu_to_le64(size);
4757 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004758 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4760 pSMB->InformationLevel =
4761 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4762 else
4763 pSMB->InformationLevel =
4764 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004765 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4767 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004768 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 else
4770 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004771 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 }
4773 pSMB->Reserved4 = 0;
4774 pSMB->hdr.smb_buf_length += byte_count;
4775 pSMB->ByteCount = cpu_to_le16(byte_count);
4776 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4777 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4778 if (rc) {
4779 cFYI(1,
4780 ("Send error in SetFileInfo (SetFileSize) = %d",
4781 rc));
4782 }
4783
4784 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004785 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786
Steve French50c2f752007-07-13 00:33:32 +00004787 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 since file handle passed in no longer valid */
4789
4790 return rc;
4791}
4792
Steve French50c2f752007-07-13 00:33:32 +00004793/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 an open handle, rather than by pathname - this is awkward due to
4795 potential access conflicts on the open, but it is unavoidable for these
4796 old servers since the only other choice is to go from 100 nanosecond DCE
4797 time and resort to the original setpathinfo level which takes the ancient
4798 DOS time format with 2 second granularity */
4799int
Steve French50c2f752007-07-13 00:33:32 +00004800CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4801 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802{
4803 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4804 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4805 char *data_offset;
4806 int rc = 0;
4807 int bytes_returned = 0;
4808 __u16 params, param_offset, offset, byte_count, count;
4809
4810 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004811 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4812
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 if (rc)
4814 return rc;
4815
Steve Frenchcd634992005-04-28 22:41:10 -07004816 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4817
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 /* At this point there is no need to override the current pid
4819 with the pid of the opener, but that could change if we someday
4820 use an existing handle (rather than opening one on the fly) */
4821 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4822 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004823
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 params = 6;
4825 pSMB->MaxSetupCount = 0;
4826 pSMB->Reserved = 0;
4827 pSMB->Flags = 0;
4828 pSMB->Timeout = 0;
4829 pSMB->Reserved2 = 0;
4830 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4831 offset = param_offset + params;
4832
Steve French50c2f752007-07-13 00:33:32 +00004833 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834
Steve French26f57362007-08-30 22:09:15 +00004835 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836 pSMB->MaxParameterCount = cpu_to_le16(2);
4837 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4838 pSMB->SetupCount = 1;
4839 pSMB->Reserved3 = 0;
4840 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4841 byte_count = 3 /* pad */ + params + count;
4842 pSMB->DataCount = cpu_to_le16(count);
4843 pSMB->ParameterCount = cpu_to_le16(params);
4844 pSMB->TotalDataCount = pSMB->DataCount;
4845 pSMB->TotalParameterCount = pSMB->ParameterCount;
4846 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4847 pSMB->DataOffset = cpu_to_le16(offset);
4848 pSMB->Fid = fid;
4849 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4850 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4851 else
4852 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4853 pSMB->Reserved4 = 0;
4854 pSMB->hdr.smb_buf_length += byte_count;
4855 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004856 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4858 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4859 if (rc) {
Steve French50c2f752007-07-13 00:33:32 +00004860 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 }
4862
Steve Frenchcd634992005-04-28 22:41:10 -07004863 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864
Steve French50c2f752007-07-13 00:33:32 +00004865 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 since file handle passed in no longer valid */
4867
4868 return rc;
4869}
4870
4871
4872int
4873CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004874 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004875 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876{
4877 TRANSACTION2_SPI_REQ *pSMB = NULL;
4878 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4879 int name_len;
4880 int rc = 0;
4881 int bytes_returned = 0;
4882 char *data_offset;
4883 __u16 params, param_offset, offset, byte_count, count;
4884
4885 cFYI(1, ("In SetTimes"));
4886
4887SetTimesRetry:
4888 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4889 (void **) &pSMBr);
4890 if (rc)
4891 return rc;
4892
4893 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4894 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004895 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004896 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 name_len++; /* trailing null */
4898 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004899 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 name_len = strnlen(fileName, PATH_MAX);
4901 name_len++; /* trailing null */
4902 strncpy(pSMB->FileName, fileName, name_len);
4903 }
4904
4905 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004906 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 pSMB->MaxParameterCount = cpu_to_le16(2);
4908 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4909 pSMB->MaxSetupCount = 0;
4910 pSMB->Reserved = 0;
4911 pSMB->Flags = 0;
4912 pSMB->Timeout = 0;
4913 pSMB->Reserved2 = 0;
4914 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004915 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 offset = param_offset + params;
4917 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4918 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4919 pSMB->DataOffset = cpu_to_le16(offset);
4920 pSMB->SetupCount = 1;
4921 pSMB->Reserved3 = 0;
4922 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4923 byte_count = 3 /* pad */ + params + count;
4924
4925 pSMB->DataCount = cpu_to_le16(count);
4926 pSMB->ParameterCount = cpu_to_le16(params);
4927 pSMB->TotalDataCount = pSMB->DataCount;
4928 pSMB->TotalParameterCount = pSMB->ParameterCount;
4929 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4930 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4931 else
4932 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4933 pSMB->Reserved4 = 0;
4934 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004935 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 pSMB->ByteCount = cpu_to_le16(byte_count);
4937 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4938 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4939 if (rc) {
4940 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4941 }
4942
4943 cifs_buf_release(pSMB);
4944
4945 if (rc == -EAGAIN)
4946 goto SetTimesRetry;
4947
4948 return rc;
4949}
4950
4951/* Can not be used to set time stamps yet (due to old DOS time format) */
4952/* Can be used to set attributes */
4953#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4954 handling it anyway and NT4 was what we thought it would be needed for
4955 Do not delete it until we prove whether needed for Win9x though */
4956int
4957CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4958 __u16 dos_attrs, const struct nls_table *nls_codepage)
4959{
4960 SETATTR_REQ *pSMB = NULL;
4961 SETATTR_RSP *pSMBr = NULL;
4962 int rc = 0;
4963 int bytes_returned;
4964 int name_len;
4965
4966 cFYI(1, ("In SetAttrLegacy"));
4967
4968SetAttrLgcyRetry:
4969 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4970 (void **) &pSMBr);
4971 if (rc)
4972 return rc;
4973
4974 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4975 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004976 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 PATH_MAX, nls_codepage);
4978 name_len++; /* trailing null */
4979 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004980 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 name_len = strnlen(fileName, PATH_MAX);
4982 name_len++; /* trailing null */
4983 strncpy(pSMB->fileName, fileName, name_len);
4984 }
4985 pSMB->attr = cpu_to_le16(dos_attrs);
4986 pSMB->BufferFormat = 0x04;
4987 pSMB->hdr.smb_buf_length += name_len + 1;
4988 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4989 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4990 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4991 if (rc) {
4992 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4993 }
4994
4995 cifs_buf_release(pSMB);
4996
4997 if (rc == -EAGAIN)
4998 goto SetAttrLgcyRetry;
4999
5000 return rc;
5001}
5002#endif /* temporarily unneeded SetAttr legacy function */
5003
5004int
5005CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00005006 char *fileName, __u64 mode, __u64 uid, __u64 gid,
5007 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07005008 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009{
5010 TRANSACTION2_SPI_REQ *pSMB = NULL;
5011 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5012 int name_len;
5013 int rc = 0;
5014 int bytes_returned = 0;
5015 FILE_UNIX_BASIC_INFO *data_offset;
5016 __u16 params, param_offset, offset, count, byte_count;
5017
5018 cFYI(1, ("In SetUID/GID/Mode"));
5019setPermsRetry:
5020 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5021 (void **) &pSMBr);
5022 if (rc)
5023 return rc;
5024
5025 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5026 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005027 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005028 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029 name_len++; /* trailing null */
5030 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005031 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032 name_len = strnlen(fileName, PATH_MAX);
5033 name_len++; /* trailing null */
5034 strncpy(pSMB->FileName, fileName, name_len);
5035 }
5036
5037 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005038 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 pSMB->MaxParameterCount = cpu_to_le16(2);
5040 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5041 pSMB->MaxSetupCount = 0;
5042 pSMB->Reserved = 0;
5043 pSMB->Flags = 0;
5044 pSMB->Timeout = 0;
5045 pSMB->Reserved2 = 0;
5046 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005047 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 offset = param_offset + params;
5049 data_offset =
5050 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5051 offset);
5052 memset(data_offset, 0, count);
5053 pSMB->DataOffset = cpu_to_le16(offset);
5054 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5055 pSMB->SetupCount = 1;
5056 pSMB->Reserved3 = 0;
5057 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5058 byte_count = 3 /* pad */ + params + count;
5059 pSMB->ParameterCount = cpu_to_le16(params);
5060 pSMB->DataCount = cpu_to_le16(count);
5061 pSMB->TotalParameterCount = pSMB->ParameterCount;
5062 pSMB->TotalDataCount = pSMB->DataCount;
5063 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5064 pSMB->Reserved4 = 0;
5065 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005066 /* Samba server ignores set of file size to zero due to bugs in some
5067 older clients, but we should be precise - we use SetFileSize to
5068 set file size and do not want to truncate file size to zero
5069 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005070 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005071 data_offset->EndOfFile = NO_CHANGE_64;
5072 data_offset->NumOfBytes = NO_CHANGE_64;
5073 data_offset->LastStatusChange = NO_CHANGE_64;
5074 data_offset->LastAccessTime = NO_CHANGE_64;
5075 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 data_offset->Uid = cpu_to_le64(uid);
5077 data_offset->Gid = cpu_to_le64(gid);
5078 /* better to leave device as zero when it is */
5079 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5080 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5081 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005082
Steve French790fe572007-07-07 19:25:05 +00005083 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005085 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005087 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005089 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005091 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005093 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005095 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5097
5098
5099 pSMB->ByteCount = cpu_to_le16(byte_count);
5100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5101 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5102 if (rc) {
5103 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5104 }
5105
5106 if (pSMB)
5107 cifs_buf_release(pSMB);
5108 if (rc == -EAGAIN)
5109 goto setPermsRetry;
5110 return rc;
5111}
5112
Steve French50c2f752007-07-13 00:33:32 +00005113int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005114 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005115 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005116 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117{
5118 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005119 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5120 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005121 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 int bytes_returned;
5123
Steve French50c2f752007-07-13 00:33:32 +00005124 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005126 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 if (rc)
5128 return rc;
5129
5130 pSMB->TotalParameterCount = 0 ;
5131 pSMB->TotalDataCount = 0;
5132 pSMB->MaxParameterCount = cpu_to_le32(2);
5133 /* BB find exact data count max from sess structure BB */
5134 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005135/* BB VERIFY verify which is correct for above BB */
5136 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5137 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5138
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 pSMB->MaxSetupCount = 4;
5140 pSMB->Reserved = 0;
5141 pSMB->ParameterOffset = 0;
5142 pSMB->DataCount = 0;
5143 pSMB->DataOffset = 0;
5144 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5145 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5146 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005147 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5149 pSMB->Reserved2 = 0;
5150 pSMB->CompletionFilter = cpu_to_le32(filter);
5151 pSMB->Fid = netfid; /* file handle always le */
5152 pSMB->ByteCount = 0;
5153
5154 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5155 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5156 if (rc) {
5157 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005158 } else {
5159 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005160 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005161 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005162 sizeof(struct dir_notify_req),
5163 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005164 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005165 dnotify_req->Pid = pSMB->hdr.Pid;
5166 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5167 dnotify_req->Mid = pSMB->hdr.Mid;
5168 dnotify_req->Tid = pSMB->hdr.Tid;
5169 dnotify_req->Uid = pSMB->hdr.Uid;
5170 dnotify_req->netfid = netfid;
5171 dnotify_req->pfile = pfile;
5172 dnotify_req->filter = filter;
5173 dnotify_req->multishot = multishot;
5174 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005175 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005176 &GlobalDnotifyReqList);
5177 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005178 } else
Steve French47c786e2005-10-11 20:03:18 -07005179 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 }
5181 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005182 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183}
5184#ifdef CONFIG_CIFS_XATTR
5185ssize_t
5186CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5187 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005188 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005189 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190{
5191 /* BB assumes one setup word */
5192 TRANSACTION2_QPI_REQ *pSMB = NULL;
5193 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5194 int rc = 0;
5195 int bytes_returned;
5196 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005197 struct fea *temp_fea;
5198 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 __u16 params, byte_count;
5200
5201 cFYI(1, ("In Query All EAs path %s", searchName));
5202QAllEAsRetry:
5203 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5204 (void **) &pSMBr);
5205 if (rc)
5206 return rc;
5207
5208 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5209 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005210 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005211 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 name_len++; /* trailing null */
5213 name_len *= 2;
5214 } else { /* BB improve the check for buffer overruns BB */
5215 name_len = strnlen(searchName, PATH_MAX);
5216 name_len++; /* trailing null */
5217 strncpy(pSMB->FileName, searchName, name_len);
5218 }
5219
Steve French50c2f752007-07-13 00:33:32 +00005220 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 pSMB->TotalDataCount = 0;
5222 pSMB->MaxParameterCount = cpu_to_le16(2);
5223 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5224 pSMB->MaxSetupCount = 0;
5225 pSMB->Reserved = 0;
5226 pSMB->Flags = 0;
5227 pSMB->Timeout = 0;
5228 pSMB->Reserved2 = 0;
5229 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005230 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 pSMB->DataCount = 0;
5232 pSMB->DataOffset = 0;
5233 pSMB->SetupCount = 1;
5234 pSMB->Reserved3 = 0;
5235 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5236 byte_count = params + 1 /* pad */ ;
5237 pSMB->TotalParameterCount = cpu_to_le16(params);
5238 pSMB->ParameterCount = pSMB->TotalParameterCount;
5239 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5240 pSMB->Reserved4 = 0;
5241 pSMB->hdr.smb_buf_length += byte_count;
5242 pSMB->ByteCount = cpu_to_le16(byte_count);
5243
5244 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5245 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5246 if (rc) {
5247 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5248 } else { /* decode response */
5249 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5250
5251 /* BB also check enough total bytes returned */
5252 /* BB we need to improve the validity checking
5253 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005254 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 rc = -EIO; /* bad smb */
5256 /* else if (pFindData){
5257 memcpy((char *) pFindData,
5258 (char *) &pSMBr->hdr.Protocol +
5259 data_offset, kl);
5260 }*/ else {
5261 /* check that length of list is not more than bcc */
5262 /* check that each entry does not go beyond length
5263 of list */
5264 /* check that each element of each entry does not
5265 go beyond end of list */
5266 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005267 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 rc = 0;
5269 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005270 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 ea_response_data = (struct fealist *)
5272 (((char *) &pSMBr->hdr.Protocol) +
5273 data_offset);
5274 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005275 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005276 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005278 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 } else {
5280 /* account for ea list len */
5281 name_len -= 4;
5282 temp_fea = ea_response_data->list;
5283 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005284 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285 __u16 value_len;
5286 name_len -= 4;
5287 temp_ptr += 4;
5288 rc += temp_fea->name_len;
5289 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005290 rc = rc + 5 + 1;
5291 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005292 memcpy(EAData, "user.", 5);
5293 EAData += 5;
5294 memcpy(EAData, temp_ptr,
5295 temp_fea->name_len);
5296 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 /* null terminate name */
5298 *EAData = 0;
5299 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005300 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 /* skip copy - calc size only */
5302 } else {
5303 /* stop before overrun buffer */
5304 rc = -ERANGE;
5305 break;
5306 }
5307 name_len -= temp_fea->name_len;
5308 temp_ptr += temp_fea->name_len;
5309 /* account for trailing null */
5310 name_len--;
5311 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005312 value_len =
5313 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 name_len -= value_len;
5315 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005316 /* BB check that temp_ptr is still
5317 within the SMB BB*/
5318
5319 /* no trailing null to account for
5320 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 /* go on to next EA */
5322 temp_fea = (struct fea *)temp_ptr;
5323 }
5324 }
5325 }
5326 }
5327 if (pSMB)
5328 cifs_buf_release(pSMB);
5329 if (rc == -EAGAIN)
5330 goto QAllEAsRetry;
5331
5332 return (ssize_t)rc;
5333}
5334
Steve French50c2f752007-07-13 00:33:32 +00005335ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5336 const unsigned char *searchName, const unsigned char *ea_name,
5337 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005338 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339{
5340 TRANSACTION2_QPI_REQ *pSMB = NULL;
5341 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5342 int rc = 0;
5343 int bytes_returned;
5344 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005345 struct fea *temp_fea;
5346 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 __u16 params, byte_count;
5348
5349 cFYI(1, ("In Query EA path %s", searchName));
5350QEARetry:
5351 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5352 (void **) &pSMBr);
5353 if (rc)
5354 return rc;
5355
5356 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5357 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005358 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005359 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360 name_len++; /* trailing null */
5361 name_len *= 2;
5362 } else { /* BB improve the check for buffer overruns BB */
5363 name_len = strnlen(searchName, PATH_MAX);
5364 name_len++; /* trailing null */
5365 strncpy(pSMB->FileName, searchName, name_len);
5366 }
5367
Steve French50c2f752007-07-13 00:33:32 +00005368 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 pSMB->TotalDataCount = 0;
5370 pSMB->MaxParameterCount = cpu_to_le16(2);
5371 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5372 pSMB->MaxSetupCount = 0;
5373 pSMB->Reserved = 0;
5374 pSMB->Flags = 0;
5375 pSMB->Timeout = 0;
5376 pSMB->Reserved2 = 0;
5377 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005378 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 pSMB->DataCount = 0;
5380 pSMB->DataOffset = 0;
5381 pSMB->SetupCount = 1;
5382 pSMB->Reserved3 = 0;
5383 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5384 byte_count = params + 1 /* pad */ ;
5385 pSMB->TotalParameterCount = cpu_to_le16(params);
5386 pSMB->ParameterCount = pSMB->TotalParameterCount;
5387 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5388 pSMB->Reserved4 = 0;
5389 pSMB->hdr.smb_buf_length += byte_count;
5390 pSMB->ByteCount = cpu_to_le16(byte_count);
5391
5392 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5393 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5394 if (rc) {
5395 cFYI(1, ("Send error in Query EA = %d", rc));
5396 } else { /* decode response */
5397 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5398
5399 /* BB also check enough total bytes returned */
5400 /* BB we need to improve the validity checking
5401 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005402 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 rc = -EIO; /* bad smb */
5404 /* else if (pFindData){
5405 memcpy((char *) pFindData,
5406 (char *) &pSMBr->hdr.Protocol +
5407 data_offset, kl);
5408 }*/ else {
5409 /* check that length of list is not more than bcc */
5410 /* check that each entry does not go beyond length
5411 of list */
5412 /* check that each element of each entry does not
5413 go beyond end of list */
5414 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005415 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 rc = -ENODATA;
5417 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005418 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 ea_response_data = (struct fealist *)
5420 (((char *) &pSMBr->hdr.Protocol) +
5421 data_offset);
5422 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005423 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005424 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005426 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 } else {
5428 /* account for ea list len */
5429 name_len -= 4;
5430 temp_fea = ea_response_data->list;
5431 temp_ptr = (char *)temp_fea;
5432 /* loop through checking if we have a matching
5433 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005434 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 __u16 value_len;
5436 name_len -= 4;
5437 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005438 value_len =
5439 le16_to_cpu(temp_fea->value_len);
5440 /* BB validate that value_len falls within SMB,
5441 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005442 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 temp_fea->name_len) == 0) {
5444 /* found a match */
5445 rc = value_len;
5446 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005447 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 memcpy(ea_value,
5449 temp_fea->name+temp_fea->name_len+1,
5450 rc);
Steve French50c2f752007-07-13 00:33:32 +00005451 /* ea values, unlike ea
5452 names, are not null
5453 terminated */
Steve French790fe572007-07-07 19:25:05 +00005454 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 /* skip copy - calc size only */
5456 } else {
Steve French50c2f752007-07-13 00:33:32 +00005457 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 rc = -ERANGE;
5459 }
5460 break;
5461 }
5462 name_len -= temp_fea->name_len;
5463 temp_ptr += temp_fea->name_len;
5464 /* account for trailing null */
5465 name_len--;
5466 temp_ptr++;
5467 name_len -= value_len;
5468 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005469 /* No trailing null to account for in
5470 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 temp_fea = (struct fea *)temp_ptr;
5472 }
Steve French50c2f752007-07-13 00:33:32 +00005473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 }
5475 }
5476 if (pSMB)
5477 cifs_buf_release(pSMB);
5478 if (rc == -EAGAIN)
5479 goto QEARetry;
5480
5481 return (ssize_t)rc;
5482}
5483
5484int
5485CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005486 const char *ea_name, const void *ea_value,
5487 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5488 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489{
5490 struct smb_com_transaction2_spi_req *pSMB = NULL;
5491 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5492 struct fealist *parm_data;
5493 int name_len;
5494 int rc = 0;
5495 int bytes_returned = 0;
5496 __u16 params, param_offset, byte_count, offset, count;
5497
5498 cFYI(1, ("In SetEA"));
5499SetEARetry:
5500 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5501 (void **) &pSMBr);
5502 if (rc)
5503 return rc;
5504
5505 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5506 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005507 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005508 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 name_len++; /* trailing null */
5510 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005511 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 name_len = strnlen(fileName, PATH_MAX);
5513 name_len++; /* trailing null */
5514 strncpy(pSMB->FileName, fileName, name_len);
5515 }
5516
5517 params = 6 + name_len;
5518
5519 /* done calculating parms using name_len of file name,
5520 now use name_len to calculate length of ea name
5521 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005522 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 name_len = 0;
5524 else
Steve French50c2f752007-07-13 00:33:32 +00005525 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526
5527 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5528 pSMB->MaxParameterCount = cpu_to_le16(2);
5529 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5530 pSMB->MaxSetupCount = 0;
5531 pSMB->Reserved = 0;
5532 pSMB->Flags = 0;
5533 pSMB->Timeout = 0;
5534 pSMB->Reserved2 = 0;
5535 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005536 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 offset = param_offset + params;
5538 pSMB->InformationLevel =
5539 cpu_to_le16(SMB_SET_FILE_EA);
5540
5541 parm_data =
5542 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5543 offset);
5544 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5545 pSMB->DataOffset = cpu_to_le16(offset);
5546 pSMB->SetupCount = 1;
5547 pSMB->Reserved3 = 0;
5548 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5549 byte_count = 3 /* pad */ + params + count;
5550 pSMB->DataCount = cpu_to_le16(count);
5551 parm_data->list_len = cpu_to_le32(count);
5552 parm_data->list[0].EA_flags = 0;
5553 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005554 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005556 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005557 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 parm_data->list[0].name[name_len] = 0;
5559 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5560 /* caller ensures that ea_value_len is less than 64K but
5561 we need to ensure that it fits within the smb */
5562
Steve French50c2f752007-07-13 00:33:32 +00005563 /*BB add length check to see if it would fit in
5564 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005565 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5566 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005567 memcpy(parm_data->list[0].name+name_len+1,
5568 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569
5570 pSMB->TotalDataCount = pSMB->DataCount;
5571 pSMB->ParameterCount = cpu_to_le16(params);
5572 pSMB->TotalParameterCount = pSMB->ParameterCount;
5573 pSMB->Reserved4 = 0;
5574 pSMB->hdr.smb_buf_length += byte_count;
5575 pSMB->ByteCount = cpu_to_le16(byte_count);
5576 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5577 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5578 if (rc) {
5579 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5580 }
5581
5582 cifs_buf_release(pSMB);
5583
5584 if (rc == -EAGAIN)
5585 goto SetEARetry;
5586
5587 return rc;
5588}
5589
5590#endif