blob: 2851d6e0d82365d858ed63dbfe282a4249019ee6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French12b3b8f2006-02-09 21:12:47 +00004 * Copyright (C) International Business Machines Corp., 2002,2006
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 */
27 /* treated slightly different for reconnection purposes since we never want */
28 /* to reuse a stale file handle and the caller knows the file handle */
29
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
Steve Frencheeac8042006-01-13 21:34:58 -080040#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
49#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000051 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 {BAD_PROT, "\2"}
53};
54#else
55static struct {
56 int index;
57 char *name;
58} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000059#ifdef CONFIG_CIFS_WEAK_PW_HASH
60 {LANMAN_PROT, "\2LM1.2X002"},
61#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 {CIFS_PROT, "\2NT LM 0.12"},
63 {BAD_PROT, "\2"}
64};
65#endif
66
Steve French39798772006-05-31 22:40:51 +000067/* define the number of elements in the cifs dialect array */
68#ifdef CONFIG_CIFS_POSIX
69#ifdef CONFIG_CIFS_WEAK_PW_HASH
70#define CIFS_NUM_PROT 3
71#else
72#define CIFS_NUM_PROT 2
73#endif /* CIFS_WEAK_PW_HASH */
74#else /* not posix */
75#ifdef CONFIG_CIFS_WEAK_PW_HASH
76#define CIFS_NUM_PROT 2
77#else
78#define CIFS_NUM_PROT 1
79#endif /* CONFIG_CIFS_WEAK_PW_HASH */
80#endif /* CIFS_POSIX */
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83/* Mark as invalid, all open files on tree connections since they
84 were closed when session to server was lost */
85static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
86{
87 struct cifsFileInfo *open_file = NULL;
88 struct list_head * tmp;
89 struct list_head * tmp1;
90
91/* list all files open on tree connection and mark them invalid */
92 write_lock(&GlobalSMBSeslock);
93 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
94 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
95 if(open_file) {
96 open_file->invalidHandle = TRUE;
97 }
98 }
99 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700100 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
101 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102}
103
104/* If the return code is zero, this function must fill in request_buf pointer */
105static int
106small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
107 void **request_buf /* returned */)
108{
109 int rc = 0;
110
111 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
112 check for tcp and smb session status done differently
113 for those three - in the calling routine */
114 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800115 if(tcon->tidStatus == CifsExiting) {
116 /* only tree disconnect, open, and write,
117 (and ulogoff which does not have tcon)
118 are allowed as we start force umount */
119 if((smb_command != SMB_COM_WRITE_ANDX) &&
120 (smb_command != SMB_COM_OPEN_ANDX) &&
121 (smb_command != SMB_COM_TREE_DISCONNECT)) {
122 cFYI(1,("can not send cmd %d while umounting",
123 smb_command));
124 return -ENODEV;
125 }
126 }
Steve French31ca3bc2005-04-28 22:41:11 -0700127 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
128 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 struct nls_table *nls_codepage;
130 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700131 reconnect, should be greater than cifs socket
132 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
134 wait_event_interruptible_timeout(tcon->ses->server->response_q,
135 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
136 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
137 /* on "soft" mounts we wait once */
138 if((tcon->retry == FALSE) ||
139 (tcon->ses->status == CifsExiting)) {
140 cFYI(1,("gave up waiting on reconnect in smb_init"));
141 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700142 } /* else "hard" mount - keep retrying
143 until process is killed or server
144 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 } else /* TCP session is reestablished now */
146 break;
147
148 }
149
150 nls_codepage = load_nls_default();
151 /* need to prevent multiple threads trying to
152 simultaneously reconnect the same SMB session */
153 down(&tcon->ses->sesSem);
154 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700155 rc = cifs_setup_session(0, tcon->ses,
156 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
158 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700159 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
160 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700162 /* BB FIXME add code to check if wsize needs
163 update due to negotiated smb buffer size
164 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 if(rc == 0)
166 atomic_inc(&tconInfoReconnectCount);
167
168 cFYI(1, ("reconnect tcon rc = %d", rc));
169 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700170 it is safer (and faster) to reopen files
171 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
173 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700174 know whether we can continue or not without
175 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 switch(smb_command) {
177 case SMB_COM_READ_ANDX:
178 case SMB_COM_WRITE_ANDX:
179 case SMB_COM_CLOSE:
180 case SMB_COM_FIND_CLOSE2:
181 case SMB_COM_LOCKING_ANDX: {
182 unload_nls(nls_codepage);
183 return -EAGAIN;
184 }
185 }
186 } else {
187 up(&tcon->ses->sesSem);
188 }
189 unload_nls(nls_codepage);
190
191 } else {
192 return -EIO;
193 }
194 }
195 if(rc)
196 return rc;
197
198 *request_buf = cifs_small_buf_get();
199 if (*request_buf == NULL) {
200 /* BB should we add a retry in here if not a writepage? */
201 return -ENOMEM;
202 }
203
204 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
205
Steve Frencha4544342005-08-24 13:59:35 -0700206 if(tcon != NULL)
207 cifs_stats_inc(&tcon->num_smbs_sent);
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000210}
211
Steve French12b3b8f2006-02-09 21:12:47 +0000212int
Steve French5815449d2006-02-14 01:36:20 +0000213small_smb_init_no_tc(const int smb_command, const int wct,
214 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000215{
216 int rc;
217 struct smb_hdr * buffer;
218
Steve French5815449d2006-02-14 01:36:20 +0000219 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French12b3b8f2006-02-09 21:12:47 +0000220 if(rc)
221 return rc;
222
Steve French04fdabe2006-02-10 05:52:50 +0000223 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000224 buffer->Mid = GetNextMid(ses->server);
225 if (ses->capabilities & CAP_UNICODE)
226 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000227 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000228 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
229
230 /* uid, tid can stay at zero as set in header assemble */
231
232 /* BB add support for turning on the signing when
233 this function is used after 1st of session setup requests */
234
235 return rc;
236}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238/* If the return code is zero, this function must fill in request_buf pointer */
239static int
240smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
241 void **request_buf /* returned */ ,
242 void **response_buf /* returned */ )
243{
244 int rc = 0;
245
246 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
247 check for tcp and smb session status done differently
248 for those three - in the calling routine */
249 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800250 if(tcon->tidStatus == CifsExiting) {
251 /* only tree disconnect, open, and write,
252 (and ulogoff which does not have tcon)
253 are allowed as we start force umount */
254 if((smb_command != SMB_COM_WRITE_ANDX) &&
255 (smb_command != SMB_COM_OPEN_ANDX) &&
256 (smb_command != SMB_COM_TREE_DISCONNECT)) {
257 cFYI(1,("can not send cmd %d while umounting",
258 smb_command));
259 return -ENODEV;
260 }
261 }
262
Steve French31ca3bc2005-04-28 22:41:11 -0700263 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
264 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700266 /* Give Demultiplex thread up to 10 seconds to
267 reconnect, should be greater than cifs socket
268 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
270 wait_event_interruptible_timeout(tcon->ses->server->response_q,
271 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700272 if(tcon->ses->server->tcpStatus ==
273 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 /* on "soft" mounts we wait once */
275 if((tcon->retry == FALSE) ||
276 (tcon->ses->status == CifsExiting)) {
277 cFYI(1,("gave up waiting on reconnect in smb_init"));
278 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700279 } /* else "hard" mount - keep retrying
280 until process is killed or server
281 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 } else /* TCP session is reestablished now */
283 break;
284
285 }
286
287 nls_codepage = load_nls_default();
288 /* need to prevent multiple threads trying to
289 simultaneously reconnect the same SMB session */
290 down(&tcon->ses->sesSem);
291 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700292 rc = cifs_setup_session(0, tcon->ses,
293 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
295 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700296 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
297 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700299 /* BB FIXME add code to check if wsize needs
300 update due to negotiated smb buffer size
301 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 if(rc == 0)
303 atomic_inc(&tconInfoReconnectCount);
304
305 cFYI(1, ("reconnect tcon rc = %d", rc));
306 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700307 it is safer (and faster) to reopen files
308 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
310 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700311 know whether we can continue or not without
312 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 switch(smb_command) {
314 case SMB_COM_READ_ANDX:
315 case SMB_COM_WRITE_ANDX:
316 case SMB_COM_CLOSE:
317 case SMB_COM_FIND_CLOSE2:
318 case SMB_COM_LOCKING_ANDX: {
319 unload_nls(nls_codepage);
320 return -EAGAIN;
321 }
322 }
323 } else {
324 up(&tcon->ses->sesSem);
325 }
326 unload_nls(nls_codepage);
327
328 } else {
329 return -EIO;
330 }
331 }
332 if(rc)
333 return rc;
334
335 *request_buf = cifs_buf_get();
336 if (*request_buf == NULL) {
337 /* BB should we add a retry in here if not a writepage? */
338 return -ENOMEM;
339 }
340 /* Although the original thought was we needed the response buf for */
341 /* potential retries of smb operations it turns out we can determine */
342 /* from the mid flags when the request buffer can be resent without */
343 /* having to use a second distinct buffer for the response */
Steve French39798772006-05-31 22:40:51 +0000344 if(response_buf)
345 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
348 wct /*wct */ );
349
Steve Frencha4544342005-08-24 13:59:35 -0700350 if(tcon != NULL)
351 cifs_stats_inc(&tcon->num_smbs_sent);
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return rc;
354}
355
356static int validate_t2(struct smb_t2_rsp * pSMB)
357{
358 int rc = -EINVAL;
359 int total_size;
360 char * pBCC;
361
362 /* check for plausible wct, bcc and t2 data and parm sizes */
363 /* check for parm and data offset going beyond end of smb */
364 if(pSMB->hdr.WordCount >= 10) {
365 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
366 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
367 /* check that bcc is at least as big as parms + data */
368 /* check that bcc is less than negotiated smb buffer */
369 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
370 if(total_size < 512) {
371 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
372 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700373 pBCC = (pSMB->hdr.WordCount * 2) +
374 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 (char *)pSMB;
376 if((total_size <= (*(u16 *)pBCC)) &&
377 (total_size <
378 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
379 return 0;
380 }
381
382 }
383 }
384 }
385 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
386 sizeof(struct smb_t2_rsp) + 16);
387 return rc;
388}
389int
390CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
391{
392 NEGOTIATE_REQ *pSMB;
393 NEGOTIATE_RSP *pSMBr;
394 int rc = 0;
395 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000396 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 struct TCP_Server_Info * server;
398 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000399 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
401 if(ses->server)
402 server = ses->server;
403 else {
404 rc = -EIO;
405 return rc;
406 }
407 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
408 (void **) &pSMB, (void **) &pSMBr);
409 if (rc)
410 return rc;
Steve French750d1152006-06-27 06:28:30 +0000411
412 /* if any of auth flags (ie not sign or seal) are overriden use them */
413 if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
414 secFlags = ses->overrideSecFlg;
415 else /* if override flags set only sign/seal OR them with global auth */
416 secFlags = extended_security | ses->overrideSecFlg;
417
Steve Frenchf40c5622006-06-28 00:13:38 +0000418 cFYI(1,("secFlags 0x%x",secFlags));
419
Steve French1982c342005-08-17 12:38:22 -0700420 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
Steve French750d1152006-06-27 06:28:30 +0000422 if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000423 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French39798772006-05-31 22:40:51 +0000424
425 count = 0;
426 for(i=0;i<CIFS_NUM_PROT;i++) {
427 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
428 count += strlen(protocols[i].name) + 1;
429 /* null at end of source and target buffers anyway */
430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 pSMB->hdr.smb_buf_length += count;
432 pSMB->ByteCount = cpu_to_le16(count);
433
434 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
435 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French254e55e2006-06-04 05:53:15 +0000436 if (rc != 0)
437 goto neg_err_exit;
438
439 cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
440 /* Check wct = 1 error case */
441 if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
442 /* core returns wct = 1, but we do not ask for core - otherwise
443 small wct just comes when dialect index is -1 indicating we
444 could not negotiate a common dialect */
445 rc = -EOPNOTSUPP;
446 goto neg_err_exit;
447#ifdef CONFIG_CIFS_WEAK_PW_HASH
448 } else if((pSMBr->hdr.WordCount == 13)
449 && (pSMBr->DialectIndex == LANMAN_PROT)) {
450 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
451
Steve French750d1152006-06-27 06:28:30 +0000452 if((secFlags & CIFSSEC_MAY_LANMAN) ||
453 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000454 server->secType = LANMAN;
455 else {
456 cERROR(1, ("mount failed weak security disabled"
457 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000458 rc = -EOPNOTSUPP;
459 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000460 }
461 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
462 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
463 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000464 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000465 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
466 /* even though we do not use raw we might as well set this
467 accurately, in case we ever find a need for it */
468 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
469 server->maxRw = 0xFF00;
470 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
471 } else {
472 server->maxRw = 0;/* we do not need to use raw anyway */
473 server->capabilities = CAP_MPX_MODE;
474 }
475 server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
Steve French39798772006-05-31 22:40:51 +0000476
Steve French254e55e2006-06-04 05:53:15 +0000477 /* BB get server time for time conversions and add
478 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000479
Steve French5ddaa682006-08-15 13:35:48 +0000480 if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000481 memcpy(server->cryptKey, rsp->EncryptionKey,
482 CIFS_CRYPTO_KEY_SIZE);
483 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
484 rc = -EIO; /* need cryptkey unless plain text */
485 goto neg_err_exit;
486 }
Steve French39798772006-05-31 22:40:51 +0000487
Steve French254e55e2006-06-04 05:53:15 +0000488 cFYI(1,("LANMAN negotiated"));
489 /* we will not end up setting signing flags - as no signing
490 was in LANMAN and server did not return the flags on */
491 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000492#else /* weak security disabled */
Steve French254e55e2006-06-04 05:53:15 +0000493 } else if(pSMBr->hdr.WordCount == 13) {
494 cERROR(1,("mount failed, cifs module not built "
495 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000496 rc = -EOPNOTSUPP;
497#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000498 goto neg_err_exit;
499 } else if(pSMBr->hdr.WordCount != 17) {
500 /* unknown wct */
501 rc = -EOPNOTSUPP;
502 goto neg_err_exit;
503 }
504 /* else wct == 17 NTLM */
505 server->secMode = pSMBr->SecurityMode;
506 if((server->secMode & SECMODE_USER) == 0)
507 cFYI(1,("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000508
Steve French254e55e2006-06-04 05:53:15 +0000509 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000510#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000511 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000512#endif /* CIFS_WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000513 cERROR(1,("Server requests plain text password"
514 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000515
Steve Frenchf40c5622006-06-28 00:13:38 +0000516 if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000517 server->secType = NTLMv2;
Steve Frenchf40c5622006-06-28 00:13:38 +0000518 else if(secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000519 server->secType = NTLM;
Steve Frenchf40c5622006-06-28 00:13:38 +0000520 else if(secFlags & CIFSSEC_MAY_NTLMV2)
521 server->secType = NTLMv2;
522 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000523
Steve French254e55e2006-06-04 05:53:15 +0000524 /* one byte, so no need to convert this or EncryptionKeyLen from
525 little endian */
526 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
527 /* probably no need to store and check maxvcs */
528 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000530 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
531 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
532 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
533 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
534 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
535 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
536 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
537 CIFS_CRYPTO_KEY_SIZE);
538 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
539 && (pSMBr->EncryptionKeyLength == 0)) {
540 /* decode security blob */
541 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
542 rc = -EIO; /* no crypt key only if plain text pwd */
543 goto neg_err_exit;
544 }
545
546 /* BB might be helpful to save off the domain of server here */
547
548 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
549 (server->capabilities & CAP_EXTENDED_SECURITY)) {
550 count = pSMBr->ByteCount;
551 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000553 else if (count == 16) {
554 server->secType = RawNTLMSSP;
555 if (server->socketUseCount.counter > 1) {
556 if (memcmp(server->server_GUID,
557 pSMBr->u.extended_response.
558 GUID, 16) != 0) {
559 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000561 pSMBr->u.extended_response.GUID,
562 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 }
Steve French254e55e2006-06-04 05:53:15 +0000564 } else
565 memcpy(server->server_GUID,
566 pSMBr->u.extended_response.GUID, 16);
567 } else {
568 rc = decode_negTokenInit(pSMBr->u.extended_response.
569 SecurityBlob,
570 count - 16,
571 &server->secType);
572 if(rc == 1) {
573 /* BB Need to fill struct for sessetup here */
574 rc = -EOPNOTSUPP;
575 } else {
576 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 }
Steve French254e55e2006-06-04 05:53:15 +0000579 } else
580 server->capabilities &= ~CAP_EXTENDED_SECURITY;
581
Steve French6344a422006-06-12 04:18:35 +0000582#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000583signing_check:
Steve French6344a422006-06-12 04:18:35 +0000584#endif
Steve French254e55e2006-06-04 05:53:15 +0000585 if(sign_CIFS_PDUs == FALSE) {
586 if(server->secMode & SECMODE_SIGN_REQUIRED)
587 cERROR(1,("Server requires "
588 "/proc/fs/cifs/PacketSigningEnabled to be on"));
589 server->secMode &=
590 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
591 } else if(sign_CIFS_PDUs == 1) {
592 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
593 server->secMode &=
594 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
595 } else if(sign_CIFS_PDUs == 2) {
596 if((server->secMode &
597 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
598 cERROR(1,("signing required but server lacks support"));
599 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 }
Steve French39798772006-05-31 22:40:51 +0000601neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700602 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000603
604 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 return rc;
606}
607
608int
609CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
610{
611 struct smb_hdr *smb_buffer;
612 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
613 int rc = 0;
614 int length;
615
616 cFYI(1, ("In tree disconnect"));
617 /*
618 * If last user of the connection and
619 * connection alive - disconnect it
620 * If this is the last connection on the server session disconnect it
621 * (and inside session disconnect we should check if tcp socket needs
622 * to be freed and kernel thread woken up).
623 */
624 if (tcon)
625 down(&tcon->tconSem);
626 else
627 return -EIO;
628
629 atomic_dec(&tcon->useCount);
630 if (atomic_read(&tcon->useCount) > 0) {
631 up(&tcon->tconSem);
632 return -EBUSY;
633 }
634
635 /* No need to return error on this operation if tid invalidated and
636 closed on server already e.g. due to tcp session crashing */
637 if(tcon->tidStatus == CifsNeedReconnect) {
638 up(&tcon->tconSem);
639 return 0;
640 }
641
642 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
643 up(&tcon->tconSem);
644 return -EIO;
645 }
Steve French09d1db52005-04-28 22:41:08 -0700646 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
647 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 if (rc) {
649 up(&tcon->tconSem);
650 return rc;
651 } else {
652 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
655 &length, 0);
656 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700657 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
659 if (smb_buffer)
660 cifs_small_buf_release(smb_buffer);
661 up(&tcon->tconSem);
662
663 /* No need to return error on this operation if tid invalidated and
664 closed on server already e.g. due to tcp session crashing */
665 if (rc == -EAGAIN)
666 rc = 0;
667
668 return rc;
669}
670
671int
672CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
673{
674 struct smb_hdr *smb_buffer_response;
675 LOGOFF_ANDX_REQ *pSMB;
676 int rc = 0;
677 int length;
678
679 cFYI(1, ("In SMBLogoff for session disconnect"));
680 if (ses)
681 down(&ses->sesSem);
682 else
683 return -EIO;
684
685 atomic_dec(&ses->inUse);
686 if (atomic_read(&ses->inUse) > 0) {
687 up(&ses->sesSem);
688 return -EBUSY;
689 }
690 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
691 if (rc) {
692 up(&ses->sesSem);
693 return rc;
694 }
695
696 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
697
698 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700699 pSMB->hdr.Mid = GetNextMid(ses->server);
700
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 if(ses->server->secMode &
702 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
703 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
704 }
705
706 pSMB->hdr.Uid = ses->Suid;
707
708 pSMB->AndXCommand = 0xFF;
709 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
710 smb_buffer_response, &length, 0);
711 if (ses->server) {
712 atomic_dec(&ses->server->socketUseCount);
713 if (atomic_read(&ses->server->socketUseCount) == 0) {
714 spin_lock(&GlobalMid_Lock);
715 ses->server->tcpStatus = CifsExiting;
716 spin_unlock(&GlobalMid_Lock);
717 rc = -ESHUTDOWN;
718 }
719 }
Steve Frencha59c6582005-08-17 12:12:19 -0700720 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700721 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723 /* if session dead then we do not need to do ulogoff,
724 since server closed smb session, no sense reporting
725 error */
726 if (rc == -EAGAIN)
727 rc = 0;
728 return rc;
729}
730
731int
Steve French737b7582005-04-28 22:41:06 -0700732CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
733 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
735 DELETE_FILE_REQ *pSMB = NULL;
736 DELETE_FILE_RSP *pSMBr = NULL;
737 int rc = 0;
738 int bytes_returned;
739 int name_len;
740
741DelFileRetry:
742 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
743 (void **) &pSMBr);
744 if (rc)
745 return rc;
746
747 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
748 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500749 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700750 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 name_len++; /* trailing null */
752 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700753 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 name_len = strnlen(fileName, PATH_MAX);
755 name_len++; /* trailing null */
756 strncpy(pSMB->fileName, fileName, name_len);
757 }
758 pSMB->SearchAttributes =
759 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
760 pSMB->BufferFormat = 0x04;
761 pSMB->hdr.smb_buf_length += name_len + 1;
762 pSMB->ByteCount = cpu_to_le16(name_len + 1);
763 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
764 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700765 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 if (rc) {
767 cFYI(1, ("Error in RMFile = %d", rc));
768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
770 cifs_buf_release(pSMB);
771 if (rc == -EAGAIN)
772 goto DelFileRetry;
773
774 return rc;
775}
776
777int
Steve French737b7582005-04-28 22:41:06 -0700778CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
779 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
781 DELETE_DIRECTORY_REQ *pSMB = NULL;
782 DELETE_DIRECTORY_RSP *pSMBr = NULL;
783 int rc = 0;
784 int bytes_returned;
785 int name_len;
786
787 cFYI(1, ("In CIFSSMBRmDir"));
788RmDirRetry:
789 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
790 (void **) &pSMBr);
791 if (rc)
792 return rc;
793
794 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700795 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
796 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 name_len++; /* trailing null */
798 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700799 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 name_len = strnlen(dirName, PATH_MAX);
801 name_len++; /* trailing null */
802 strncpy(pSMB->DirName, dirName, name_len);
803 }
804
805 pSMB->BufferFormat = 0x04;
806 pSMB->hdr.smb_buf_length += name_len + 1;
807 pSMB->ByteCount = cpu_to_le16(name_len + 1);
808 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
809 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700810 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 if (rc) {
812 cFYI(1, ("Error in RMDir = %d", rc));
813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
815 cifs_buf_release(pSMB);
816 if (rc == -EAGAIN)
817 goto RmDirRetry;
818 return rc;
819}
820
821int
822CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700823 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824{
825 int rc = 0;
826 CREATE_DIRECTORY_REQ *pSMB = NULL;
827 CREATE_DIRECTORY_RSP *pSMBr = NULL;
828 int bytes_returned;
829 int name_len;
830
831 cFYI(1, ("In CIFSSMBMkDir"));
832MkDirRetry:
833 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
834 (void **) &pSMBr);
835 if (rc)
836 return rc;
837
838 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500839 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700840 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 name_len++; /* trailing null */
842 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700843 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 name_len = strnlen(name, PATH_MAX);
845 name_len++; /* trailing null */
846 strncpy(pSMB->DirName, name, name_len);
847 }
848
849 pSMB->BufferFormat = 0x04;
850 pSMB->hdr.smb_buf_length += name_len + 1;
851 pSMB->ByteCount = cpu_to_le16(name_len + 1);
852 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
853 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700854 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 if (rc) {
856 cFYI(1, ("Error in Mkdir = %d", rc));
857 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700858
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 cifs_buf_release(pSMB);
860 if (rc == -EAGAIN)
861 goto MkDirRetry;
862 return rc;
863}
864
Steve Frencha9d02ad2005-08-24 23:06:05 -0700865static __u16 convert_disposition(int disposition)
866{
867 __u16 ofun = 0;
868
869 switch (disposition) {
870 case FILE_SUPERSEDE:
871 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
872 break;
873 case FILE_OPEN:
874 ofun = SMBOPEN_OAPPEND;
875 break;
876 case FILE_CREATE:
877 ofun = SMBOPEN_OCREATE;
878 break;
879 case FILE_OPEN_IF:
880 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
881 break;
882 case FILE_OVERWRITE:
883 ofun = SMBOPEN_OTRUNC;
884 break;
885 case FILE_OVERWRITE_IF:
886 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
887 break;
888 default:
889 cFYI(1,("unknown disposition %d",disposition));
890 ofun = SMBOPEN_OAPPEND; /* regular open */
891 }
892 return ofun;
893}
894
895int
896SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
897 const char *fileName, const int openDisposition,
898 const int access_flags, const int create_options, __u16 * netfid,
899 int *pOplock, FILE_ALL_INFO * pfile_info,
900 const struct nls_table *nls_codepage, int remap)
901{
902 int rc = -EACCES;
903 OPENX_REQ *pSMB = NULL;
904 OPENX_RSP *pSMBr = NULL;
905 int bytes_returned;
906 int name_len;
907 __u16 count;
908
909OldOpenRetry:
910 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
911 (void **) &pSMBr);
912 if (rc)
913 return rc;
914
915 pSMB->AndXCommand = 0xFF; /* none */
916
917 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
918 count = 1; /* account for one byte pad to word boundary */
919 name_len =
920 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
921 fileName, PATH_MAX, nls_codepage, remap);
922 name_len++; /* trailing null */
923 name_len *= 2;
924 } else { /* BB improve check for buffer overruns BB */
925 count = 0; /* no pad */
926 name_len = strnlen(fileName, PATH_MAX);
927 name_len++; /* trailing null */
928 strncpy(pSMB->fileName, fileName, name_len);
929 }
930 if (*pOplock & REQ_OPLOCK)
931 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
932 else if (*pOplock & REQ_BATCHOPLOCK) {
933 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
934 }
935 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
936 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
937 /* 0 = read
938 1 = write
939 2 = rw
940 3 = execute
941 */
942 pSMB->Mode = cpu_to_le16(2);
943 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
944 /* set file as system file if special file such
945 as fifo and server expecting SFU style and
946 no Unix extensions */
947
948 if(create_options & CREATE_OPTION_SPECIAL)
949 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
950 else
Steve French3e87d802005-09-18 20:49:21 -0700951 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700952
953 /* if ((omode & S_IWUGO) == 0)
954 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
955 /* Above line causes problems due to vfs splitting create into two
956 pieces - need to set mode after file created not while it is
957 being created */
958
959 /* BB FIXME BB */
960/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
961 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700962
963 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700964 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700965 count += name_len;
966 pSMB->hdr.smb_buf_length += count;
967
968 pSMB->ByteCount = cpu_to_le16(count);
969 /* long_op set to 1 to allow for oplock break timeouts */
970 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
971 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
972 cifs_stats_inc(&tcon->num_opens);
973 if (rc) {
974 cFYI(1, ("Error in Open = %d", rc));
975 } else {
976 /* BB verify if wct == 15 */
977
978/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
979
980 *netfid = pSMBr->Fid; /* cifs fid stays in le */
981 /* Let caller know file was created so we can set the mode. */
982 /* Do we care about the CreateAction in any other cases? */
983 /* BB FIXME BB */
984/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
985 *pOplock |= CIFS_CREATE_ACTION; */
986 /* BB FIXME END */
987
988 if(pfile_info) {
989 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
990 pfile_info->LastAccessTime = 0; /* BB fixme */
991 pfile_info->LastWriteTime = 0; /* BB fixme */
992 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700993 pfile_info->Attributes =
994 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700995 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700996 pfile_info->AllocationSize =
997 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
998 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700999 pfile_info->NumberOfLinks = cpu_to_le32(1);
1000 }
1001 }
1002
1003 cifs_buf_release(pSMB);
1004 if (rc == -EAGAIN)
1005 goto OldOpenRetry;
1006 return rc;
1007}
1008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009int
1010CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1011 const char *fileName, const int openDisposition,
1012 const int access_flags, const int create_options, __u16 * netfid,
1013 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001014 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015{
1016 int rc = -EACCES;
1017 OPEN_REQ *pSMB = NULL;
1018 OPEN_RSP *pSMBr = NULL;
1019 int bytes_returned;
1020 int name_len;
1021 __u16 count;
1022
1023openRetry:
1024 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1025 (void **) &pSMBr);
1026 if (rc)
1027 return rc;
1028
1029 pSMB->AndXCommand = 0xFF; /* none */
1030
1031 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1032 count = 1; /* account for one byte pad to word boundary */
1033 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001034 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001035 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 name_len++; /* trailing null */
1037 name_len *= 2;
1038 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001039 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 count = 0; /* no pad */
1041 name_len = strnlen(fileName, PATH_MAX);
1042 name_len++; /* trailing null */
1043 pSMB->NameLength = cpu_to_le16(name_len);
1044 strncpy(pSMB->fileName, fileName, name_len);
1045 }
1046 if (*pOplock & REQ_OPLOCK)
1047 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1048 else if (*pOplock & REQ_BATCHOPLOCK) {
1049 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1050 }
1051 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1052 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001053 /* set file as system file if special file such
1054 as fifo and server expecting SFU style and
1055 no Unix extensions */
1056 if(create_options & CREATE_OPTION_SPECIAL)
1057 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1058 else
1059 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 /* XP does not handle ATTR_POSIX_SEMANTICS */
1061 /* but it helps speed up case sensitive checks for other
1062 servers such as Samba */
1063 if (tcon->ses->capabilities & CAP_UNIX)
1064 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1065
1066 /* if ((omode & S_IWUGO) == 0)
1067 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1068 /* Above line causes problems due to vfs splitting create into two
1069 pieces - need to set mode after file created not while it is
1070 being created */
1071 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1072 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001073 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001074 /* BB Expirement with various impersonation levels and verify */
1075 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 pSMB->SecurityFlags =
1077 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1078
1079 count += name_len;
1080 pSMB->hdr.smb_buf_length += count;
1081
1082 pSMB->ByteCount = cpu_to_le16(count);
1083 /* long_op set to 1 to allow for oplock break timeouts */
1084 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1085 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001086 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 if (rc) {
1088 cFYI(1, ("Error in Open = %d", rc));
1089 } else {
Steve French09d1db52005-04-28 22:41:08 -07001090 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1092 /* Let caller know file was created so we can set the mode. */
1093 /* Do we care about the CreateAction in any other cases? */
1094 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1095 *pOplock |= CIFS_CREATE_ACTION;
1096 if(pfile_info) {
1097 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1098 36 /* CreationTime to Attributes */);
1099 /* the file_info buf is endian converted by caller */
1100 pfile_info->AllocationSize = pSMBr->AllocationSize;
1101 pfile_info->EndOfFile = pSMBr->EndOfFile;
1102 pfile_info->NumberOfLinks = cpu_to_le32(1);
1103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 cifs_buf_release(pSMB);
1107 if (rc == -EAGAIN)
1108 goto openRetry;
1109 return rc;
1110}
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112int
1113CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001114 const int netfid, const unsigned int count,
1115 const __u64 lseek, unsigned int *nbytes, char **buf,
1116 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117{
1118 int rc = -EACCES;
1119 READ_REQ *pSMB = NULL;
1120 READ_RSP *pSMBr = NULL;
1121 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001122 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001123 int resp_buf_type = 0;
1124 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001127 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1128 wct = 12;
1129 else
1130 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
1132 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001133 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 if (rc)
1135 return rc;
1136
1137 /* tcon and ses pointer are checked in smb_init */
1138 if (tcon->ses->server == NULL)
1139 return -ECONNABORTED;
1140
Steve Frenchec637e32005-12-12 20:53:18 -08001141 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 pSMB->Fid = netfid;
1143 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001144 if(wct == 12)
1145 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001146 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1147 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001148
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 pSMB->Remaining = 0;
1150 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1151 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001152 if(wct == 12)
1153 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1154 else {
1155 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001156 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001157 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001158 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001159 }
Steve Frenchec637e32005-12-12 20:53:18 -08001160
1161 iov[0].iov_base = (char *)pSMB;
1162 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1163 rc = SendReceive2(xid, tcon->ses, iov,
1164 1 /* num iovecs */,
1165 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001166 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001167 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 if (rc) {
1169 cERROR(1, ("Send error in read = %d", rc));
1170 } else {
1171 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1172 data_length = data_length << 16;
1173 data_length += le16_to_cpu(pSMBr->DataLength);
1174 *nbytes = data_length;
1175
1176 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001177 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 || (data_length > count)) {
1179 cFYI(1,("bad length %d for count %d",data_length,count));
1180 rc = -EIO;
1181 *nbytes = 0;
1182 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001183 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001185/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1186 cERROR(1,("Faulting on read rc = %d",rc));
1187 rc = -EFAULT;
1188 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001190 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 }
1192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
Steve French4b8f9302006-02-26 16:41:18 +00001194/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001195 if(*buf) {
1196 if(resp_buf_type == CIFS_SMALL_BUFFER)
1197 cifs_small_buf_release(iov[0].iov_base);
1198 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1199 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001200 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1201 /* return buffer to caller to free */
1202 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001203 if(resp_buf_type == CIFS_SMALL_BUFFER)
1204 *pbuf_type = CIFS_SMALL_BUFFER;
1205 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1206 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001207 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001208
1209 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 since file handle passed in no longer valid */
1211 return rc;
1212}
1213
Steve Frenchec637e32005-12-12 20:53:18 -08001214
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215int
1216CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1217 const int netfid, const unsigned int count,
1218 const __u64 offset, unsigned int *nbytes, const char *buf,
1219 const char __user * ubuf, const int long_op)
1220{
1221 int rc = -EACCES;
1222 WRITE_REQ *pSMB = NULL;
1223 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001224 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 __u32 bytes_sent;
1226 __u16 byte_count;
1227
1228 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001229 if(tcon->ses == NULL)
1230 return -ECONNABORTED;
1231
1232 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1233 wct = 14;
1234 else
1235 wct = 12;
1236
1237 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 (void **) &pSMBr);
1239 if (rc)
1240 return rc;
1241 /* tcon and ses pointer are checked in smb_init */
1242 if (tcon->ses->server == NULL)
1243 return -ECONNABORTED;
1244
1245 pSMB->AndXCommand = 0xFF; /* none */
1246 pSMB->Fid = netfid;
1247 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001248 if(wct == 14)
1249 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1250 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1251 return -EIO;
1252
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 pSMB->Reserved = 0xFFFFFFFF;
1254 pSMB->WriteMode = 0;
1255 pSMB->Remaining = 0;
1256
1257 /* Can increase buffer size if buffer is big enough in some cases - ie we
1258 can send more if LARGE_WRITE_X capability returned by the server and if
1259 our buffer is big enough or if we convert to iovecs on socket writes
1260 and eliminate the copy to the CIFS buffer */
1261 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1262 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1263 } else {
1264 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1265 & ~0xFF;
1266 }
1267
1268 if (bytes_sent > count)
1269 bytes_sent = count;
1270 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001271 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 if(buf)
1273 memcpy(pSMB->Data,buf,bytes_sent);
1274 else if(ubuf) {
1275 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1276 cifs_buf_release(pSMB);
1277 return -EFAULT;
1278 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001279 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 /* No buffer */
1281 cifs_buf_release(pSMB);
1282 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001283 } /* else setting file size with write of zero bytes */
1284 if(wct == 14)
1285 byte_count = bytes_sent + 1; /* pad */
1286 else /* wct == 12 */ {
1287 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1290 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001291 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001292
1293 if(wct == 14)
1294 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001295 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001296 struct smb_com_writex_req * pSMBW =
1297 (struct smb_com_writex_req *)pSMB;
1298 pSMBW->ByteCount = cpu_to_le16(byte_count);
1299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
1301 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1302 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001303 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 if (rc) {
1305 cFYI(1, ("Send error in write = %d", rc));
1306 *nbytes = 0;
1307 } else {
1308 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1309 *nbytes = (*nbytes) << 16;
1310 *nbytes += le16_to_cpu(pSMBr->Count);
1311 }
1312
1313 cifs_buf_release(pSMB);
1314
1315 /* Note: On -EAGAIN error only caller can retry on handle based calls
1316 since file handle passed in no longer valid */
1317
1318 return rc;
1319}
1320
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001321int
1322CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001324 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1325 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326{
1327 int rc = -EACCES;
1328 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001329 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001330 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001331 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Steve Frenchff7feac2005-11-15 16:45:16 -08001333 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1334
Steve French8cc64c62005-10-03 13:49:43 -07001335 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1336 wct = 14;
1337 else
1338 wct = 12;
1339 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 if (rc)
1341 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 /* tcon and ses pointer are checked in smb_init */
1343 if (tcon->ses->server == NULL)
1344 return -ECONNABORTED;
1345
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001346 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 pSMB->Fid = netfid;
1348 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001349 if(wct == 14)
1350 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1351 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1352 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 pSMB->Reserved = 0xFFFFFFFF;
1354 pSMB->WriteMode = 0;
1355 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001356
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 pSMB->DataOffset =
1358 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1359
Steve French3e844692005-10-03 13:37:24 -07001360 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1361 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001362 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001363 if(wct == 14)
1364 pSMB->hdr.smb_buf_length += count+1;
1365 else /* wct == 12 */
1366 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1367 if(wct == 14)
1368 pSMB->ByteCount = cpu_to_le16(count + 1);
1369 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1370 struct smb_com_writex_req * pSMBW =
1371 (struct smb_com_writex_req *)pSMB;
1372 pSMBW->ByteCount = cpu_to_le16(count + 5);
1373 }
Steve French3e844692005-10-03 13:37:24 -07001374 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001375 if(wct == 14)
1376 iov[0].iov_len = smb_hdr_len + 4;
1377 else /* wct == 12 pad bigger by four bytes */
1378 iov[0].iov_len = smb_hdr_len + 8;
1379
Steve French3e844692005-10-03 13:37:24 -07001380
Steve Frenchec637e32005-12-12 20:53:18 -08001381 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001382 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001383 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001385 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001387 } else if(resp_buf_type == 0) {
1388 /* presumably this can not happen, but best to be safe */
1389 rc = -EIO;
1390 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001391 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001392 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001393 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1394 *nbytes = (*nbytes) << 16;
1395 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
Steve French4b8f9302006-02-26 16:41:18 +00001398/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001399 if(resp_buf_type == CIFS_SMALL_BUFFER)
1400 cifs_small_buf_release(iov[0].iov_base);
1401 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1402 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
1404 /* Note: On -EAGAIN error only caller can retry on handle based calls
1405 since file handle passed in no longer valid */
1406
1407 return rc;
1408}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001409
1410
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411int
1412CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1413 const __u16 smb_file_id, const __u64 len,
1414 const __u64 offset, const __u32 numUnlock,
1415 const __u32 numLock, const __u8 lockType, const int waitFlag)
1416{
1417 int rc = 0;
1418 LOCK_REQ *pSMB = NULL;
1419 LOCK_RSP *pSMBr = NULL;
1420 int bytes_returned;
1421 int timeout = 0;
1422 __u16 count;
1423
1424 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001425 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1426
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 if (rc)
1428 return rc;
1429
Steve French46810cb2005-04-28 22:41:09 -07001430 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1431
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1433 timeout = -1; /* no response expected */
1434 pSMB->Timeout = 0;
1435 } else if (waitFlag == TRUE) {
1436 timeout = 3; /* blocking operation, no timeout */
1437 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1438 } else {
1439 pSMB->Timeout = 0;
1440 }
1441
1442 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1443 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1444 pSMB->LockType = lockType;
1445 pSMB->AndXCommand = 0xFF; /* none */
1446 pSMB->Fid = smb_file_id; /* netfid stays le */
1447
1448 if((numLock != 0) || (numUnlock != 0)) {
1449 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1450 /* BB where to store pid high? */
1451 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1452 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1453 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1454 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1455 count = sizeof(LOCKING_ANDX_RANGE);
1456 } else {
1457 /* oplock break */
1458 count = 0;
1459 }
1460 pSMB->hdr.smb_buf_length += count;
1461 pSMB->ByteCount = cpu_to_le16(count);
1462
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001463 if (waitFlag) {
1464 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1465 (struct smb_hdr *) pSMBr, &bytes_returned);
1466 } else {
1467 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001469 }
Steve Frencha4544342005-08-24 13:59:35 -07001470 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 if (rc) {
1472 cFYI(1, ("Send error in Lock = %d", rc));
1473 }
Steve French46810cb2005-04-28 22:41:09 -07001474 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
1476 /* Note: On -EAGAIN error only caller can retry on handle based calls
1477 since file handle passed in no longer valid */
1478 return rc;
1479}
1480
1481int
Steve French08547b02006-02-28 22:39:25 +00001482CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1483 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001484 struct file_lock *pLockData, const __u16 lock_type,
1485 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001486{
1487 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1488 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1489 char *data_offset;
1490 struct cifs_posix_lock *parm_data;
1491 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001492 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001493 int bytes_returned = 0;
1494 __u16 params, param_offset, offset, byte_count, count;
1495
1496 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001497
1498 if(pLockData == NULL)
1499 return EINVAL;
1500
Steve French08547b02006-02-28 22:39:25 +00001501 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1502
1503 if (rc)
1504 return rc;
1505
1506 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1507
1508 params = 6;
1509 pSMB->MaxSetupCount = 0;
1510 pSMB->Reserved = 0;
1511 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001512 pSMB->Reserved2 = 0;
1513 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1514 offset = param_offset + params;
1515
1516 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1517
1518 count = sizeof(struct cifs_posix_lock);
1519 pSMB->MaxParameterCount = cpu_to_le16(2);
1520 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1521 pSMB->SetupCount = 1;
1522 pSMB->Reserved3 = 0;
1523 if(get_flag)
1524 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1525 else
1526 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1527 byte_count = 3 /* pad */ + params + count;
1528 pSMB->DataCount = cpu_to_le16(count);
1529 pSMB->ParameterCount = cpu_to_le16(params);
1530 pSMB->TotalDataCount = pSMB->DataCount;
1531 pSMB->TotalParameterCount = pSMB->ParameterCount;
1532 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1533 parm_data = (struct cifs_posix_lock *)
1534 (((char *) &pSMB->hdr.Protocol) + offset);
1535
1536 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French3a5ff612006-07-14 22:37:11 +00001537 if(waitFlag) {
1538 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001539 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001540 pSMB->Timeout = cpu_to_le32(-1);
1541 } else
1542 pSMB->Timeout = 0;
1543
Steve French08547b02006-02-28 22:39:25 +00001544 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001545 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001546 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001547
1548 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001549 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001550 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1551 pSMB->Reserved4 = 0;
1552 pSMB->hdr.smb_buf_length += byte_count;
1553 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001554 if (waitFlag) {
1555 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1556 (struct smb_hdr *) pSMBr, &bytes_returned);
1557 } else {
1558 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001559 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001560 }
1561
Steve French08547b02006-02-28 22:39:25 +00001562 if (rc) {
1563 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001564 } else if (get_flag) {
1565 /* lock structure can be returned on get */
1566 __u16 data_offset;
1567 __u16 data_count;
1568 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001569
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001570 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1571 rc = -EIO; /* bad smb */
1572 goto plk_err_exit;
1573 }
1574 if(pLockData == NULL) {
1575 rc = -EINVAL;
1576 goto plk_err_exit;
1577 }
1578 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1579 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1580 if(data_count < sizeof(struct cifs_posix_lock)) {
1581 rc = -EIO;
1582 goto plk_err_exit;
1583 }
1584 parm_data = (struct cifs_posix_lock *)
1585 ((char *)&pSMBr->hdr.Protocol + data_offset);
1586 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1587 pLockData->fl_type = F_UNLCK;
1588 }
1589
1590plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001591 if (pSMB)
1592 cifs_small_buf_release(pSMB);
1593
1594 /* Note: On -EAGAIN error only caller can retry on handle based calls
1595 since file handle passed in no longer valid */
1596
1597 return rc;
1598}
1599
1600
1601int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1603{
1604 int rc = 0;
1605 CLOSE_REQ *pSMB = NULL;
1606 CLOSE_RSP *pSMBr = NULL;
1607 int bytes_returned;
1608 cFYI(1, ("In CIFSSMBClose"));
1609
1610/* do not retry on dead session on close */
1611 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1612 if(rc == -EAGAIN)
1613 return 0;
1614 if (rc)
1615 return rc;
1616
1617 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1618
1619 pSMB->FileID = (__u16) smb_file_id;
1620 pSMB->LastWriteTime = 0;
1621 pSMB->ByteCount = 0;
1622 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1623 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001624 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 if (rc) {
1626 if(rc!=-EINTR) {
1627 /* EINTR is expected when user ctl-c to kill app */
1628 cERROR(1, ("Send error in Close = %d", rc));
1629 }
1630 }
1631
1632 cifs_small_buf_release(pSMB);
1633
1634 /* Since session is dead, file will be closed on server already */
1635 if(rc == -EAGAIN)
1636 rc = 0;
1637
1638 return rc;
1639}
1640
1641int
1642CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1643 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001644 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645{
1646 int rc = 0;
1647 RENAME_REQ *pSMB = NULL;
1648 RENAME_RSP *pSMBr = NULL;
1649 int bytes_returned;
1650 int name_len, name_len2;
1651 __u16 count;
1652
1653 cFYI(1, ("In CIFSSMBRename"));
1654renameRetry:
1655 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1656 (void **) &pSMBr);
1657 if (rc)
1658 return rc;
1659
1660 pSMB->BufferFormat = 0x04;
1661 pSMB->SearchAttributes =
1662 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1663 ATTR_DIRECTORY);
1664
1665 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1666 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001667 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001668 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 name_len++; /* trailing null */
1670 name_len *= 2;
1671 pSMB->OldFileName[name_len] = 0x04; /* pad */
1672 /* protocol requires ASCII signature byte on Unicode string */
1673 pSMB->OldFileName[name_len + 1] = 0x00;
1674 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001675 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001676 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1678 name_len2 *= 2; /* convert to bytes */
1679 } else { /* BB improve the check for buffer overruns BB */
1680 name_len = strnlen(fromName, PATH_MAX);
1681 name_len++; /* trailing null */
1682 strncpy(pSMB->OldFileName, fromName, name_len);
1683 name_len2 = strnlen(toName, PATH_MAX);
1684 name_len2++; /* trailing null */
1685 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1686 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1687 name_len2++; /* trailing null */
1688 name_len2++; /* signature byte */
1689 }
1690
1691 count = 1 /* 1st signature byte */ + name_len + name_len2;
1692 pSMB->hdr.smb_buf_length += count;
1693 pSMB->ByteCount = cpu_to_le16(count);
1694
1695 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1696 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001697 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 if (rc) {
1699 cFYI(1, ("Send error in rename = %d", rc));
1700 }
1701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 cifs_buf_release(pSMB);
1703
1704 if (rc == -EAGAIN)
1705 goto renameRetry;
1706
1707 return rc;
1708}
1709
1710int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001711 int netfid, char * target_name,
1712 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713{
1714 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1715 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1716 struct set_file_rename * rename_info;
1717 char *data_offset;
1718 char dummy_string[30];
1719 int rc = 0;
1720 int bytes_returned = 0;
1721 int len_of_str;
1722 __u16 params, param_offset, offset, count, byte_count;
1723
1724 cFYI(1, ("Rename to File by handle"));
1725 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1726 (void **) &pSMBr);
1727 if (rc)
1728 return rc;
1729
1730 params = 6;
1731 pSMB->MaxSetupCount = 0;
1732 pSMB->Reserved = 0;
1733 pSMB->Flags = 0;
1734 pSMB->Timeout = 0;
1735 pSMB->Reserved2 = 0;
1736 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1737 offset = param_offset + params;
1738
1739 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1740 rename_info = (struct set_file_rename *) data_offset;
1741 pSMB->MaxParameterCount = cpu_to_le16(2);
1742 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1743 pSMB->SetupCount = 1;
1744 pSMB->Reserved3 = 0;
1745 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1746 byte_count = 3 /* pad */ + params;
1747 pSMB->ParameterCount = cpu_to_le16(params);
1748 pSMB->TotalParameterCount = pSMB->ParameterCount;
1749 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1750 pSMB->DataOffset = cpu_to_le16(offset);
1751 /* construct random name ".cifs_tmp<inodenum><mid>" */
1752 rename_info->overwrite = cpu_to_le32(1);
1753 rename_info->root_fid = 0;
1754 /* unicode only call */
1755 if(target_name == NULL) {
1756 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001757 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001758 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001760 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001761 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 }
1763 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1764 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1765 byte_count += count;
1766 pSMB->DataCount = cpu_to_le16(count);
1767 pSMB->TotalDataCount = pSMB->DataCount;
1768 pSMB->Fid = netfid;
1769 pSMB->InformationLevel =
1770 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1771 pSMB->Reserved4 = 0;
1772 pSMB->hdr.smb_buf_length += byte_count;
1773 pSMB->ByteCount = cpu_to_le16(byte_count);
1774 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1775 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001776 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 if (rc) {
1778 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1779 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 cifs_buf_release(pSMB);
1782
1783 /* Note: On -EAGAIN error only caller can retry on handle based calls
1784 since file handle passed in no longer valid */
1785
1786 return rc;
1787}
1788
1789int
1790CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1791 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001792 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793{
1794 int rc = 0;
1795 COPY_REQ *pSMB = NULL;
1796 COPY_RSP *pSMBr = NULL;
1797 int bytes_returned;
1798 int name_len, name_len2;
1799 __u16 count;
1800
1801 cFYI(1, ("In CIFSSMBCopy"));
1802copyRetry:
1803 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1804 (void **) &pSMBr);
1805 if (rc)
1806 return rc;
1807
1808 pSMB->BufferFormat = 0x04;
1809 pSMB->Tid2 = target_tid;
1810
1811 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1812
1813 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001814 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001815 fromName, PATH_MAX, nls_codepage,
1816 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 name_len++; /* trailing null */
1818 name_len *= 2;
1819 pSMB->OldFileName[name_len] = 0x04; /* pad */
1820 /* protocol requires ASCII signature byte on Unicode string */
1821 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001822 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001823 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1825 name_len2 *= 2; /* convert to bytes */
1826 } else { /* BB improve the check for buffer overruns BB */
1827 name_len = strnlen(fromName, PATH_MAX);
1828 name_len++; /* trailing null */
1829 strncpy(pSMB->OldFileName, fromName, name_len);
1830 name_len2 = strnlen(toName, PATH_MAX);
1831 name_len2++; /* trailing null */
1832 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1833 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1834 name_len2++; /* trailing null */
1835 name_len2++; /* signature byte */
1836 }
1837
1838 count = 1 /* 1st signature byte */ + name_len + name_len2;
1839 pSMB->hdr.smb_buf_length += count;
1840 pSMB->ByteCount = cpu_to_le16(count);
1841
1842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1843 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1844 if (rc) {
1845 cFYI(1, ("Send error in copy = %d with %d files copied",
1846 rc, le16_to_cpu(pSMBr->CopyCount)));
1847 }
1848 if (pSMB)
1849 cifs_buf_release(pSMB);
1850
1851 if (rc == -EAGAIN)
1852 goto copyRetry;
1853
1854 return rc;
1855}
1856
1857int
1858CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1859 const char *fromName, const char *toName,
1860 const struct nls_table *nls_codepage)
1861{
1862 TRANSACTION2_SPI_REQ *pSMB = NULL;
1863 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1864 char *data_offset;
1865 int name_len;
1866 int name_len_target;
1867 int rc = 0;
1868 int bytes_returned = 0;
1869 __u16 params, param_offset, offset, byte_count;
1870
1871 cFYI(1, ("In Symlink Unix style"));
1872createSymLinkRetry:
1873 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1874 (void **) &pSMBr);
1875 if (rc)
1876 return rc;
1877
1878 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1879 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001880 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 /* find define for this maxpathcomponent */
1882 , nls_codepage);
1883 name_len++; /* trailing null */
1884 name_len *= 2;
1885
1886 } else { /* BB improve the check for buffer overruns BB */
1887 name_len = strnlen(fromName, PATH_MAX);
1888 name_len++; /* trailing null */
1889 strncpy(pSMB->FileName, fromName, name_len);
1890 }
1891 params = 6 + name_len;
1892 pSMB->MaxSetupCount = 0;
1893 pSMB->Reserved = 0;
1894 pSMB->Flags = 0;
1895 pSMB->Timeout = 0;
1896 pSMB->Reserved2 = 0;
1897 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1898 InformationLevel) - 4;
1899 offset = param_offset + params;
1900
1901 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1902 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1903 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001904 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 /* find define for this maxpathcomponent */
1906 , nls_codepage);
1907 name_len_target++; /* trailing null */
1908 name_len_target *= 2;
1909 } else { /* BB improve the check for buffer overruns BB */
1910 name_len_target = strnlen(toName, PATH_MAX);
1911 name_len_target++; /* trailing null */
1912 strncpy(data_offset, toName, name_len_target);
1913 }
1914
1915 pSMB->MaxParameterCount = cpu_to_le16(2);
1916 /* BB find exact max on data count below from sess */
1917 pSMB->MaxDataCount = cpu_to_le16(1000);
1918 pSMB->SetupCount = 1;
1919 pSMB->Reserved3 = 0;
1920 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1921 byte_count = 3 /* pad */ + params + name_len_target;
1922 pSMB->DataCount = cpu_to_le16(name_len_target);
1923 pSMB->ParameterCount = cpu_to_le16(params);
1924 pSMB->TotalDataCount = pSMB->DataCount;
1925 pSMB->TotalParameterCount = pSMB->ParameterCount;
1926 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1927 pSMB->DataOffset = cpu_to_le16(offset);
1928 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1929 pSMB->Reserved4 = 0;
1930 pSMB->hdr.smb_buf_length += byte_count;
1931 pSMB->ByteCount = cpu_to_le16(byte_count);
1932 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1933 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001934 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 if (rc) {
1936 cFYI(1,
1937 ("Send error in SetPathInfo (create symlink) = %d",
1938 rc));
1939 }
1940
1941 if (pSMB)
1942 cifs_buf_release(pSMB);
1943
1944 if (rc == -EAGAIN)
1945 goto createSymLinkRetry;
1946
1947 return rc;
1948}
1949
1950int
1951CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1952 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001953 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954{
1955 TRANSACTION2_SPI_REQ *pSMB = NULL;
1956 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1957 char *data_offset;
1958 int name_len;
1959 int name_len_target;
1960 int rc = 0;
1961 int bytes_returned = 0;
1962 __u16 params, param_offset, offset, byte_count;
1963
1964 cFYI(1, ("In Create Hard link Unix style"));
1965createHardLinkRetry:
1966 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1967 (void **) &pSMBr);
1968 if (rc)
1969 return rc;
1970
1971 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001972 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001973 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 name_len++; /* trailing null */
1975 name_len *= 2;
1976
1977 } else { /* BB improve the check for buffer overruns BB */
1978 name_len = strnlen(toName, PATH_MAX);
1979 name_len++; /* trailing null */
1980 strncpy(pSMB->FileName, toName, name_len);
1981 }
1982 params = 6 + name_len;
1983 pSMB->MaxSetupCount = 0;
1984 pSMB->Reserved = 0;
1985 pSMB->Flags = 0;
1986 pSMB->Timeout = 0;
1987 pSMB->Reserved2 = 0;
1988 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1989 InformationLevel) - 4;
1990 offset = param_offset + params;
1991
1992 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1993 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1994 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001995 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001996 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 name_len_target++; /* trailing null */
1998 name_len_target *= 2;
1999 } else { /* BB improve the check for buffer overruns BB */
2000 name_len_target = strnlen(fromName, PATH_MAX);
2001 name_len_target++; /* trailing null */
2002 strncpy(data_offset, fromName, name_len_target);
2003 }
2004
2005 pSMB->MaxParameterCount = cpu_to_le16(2);
2006 /* BB find exact max on data count below from sess*/
2007 pSMB->MaxDataCount = cpu_to_le16(1000);
2008 pSMB->SetupCount = 1;
2009 pSMB->Reserved3 = 0;
2010 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2011 byte_count = 3 /* pad */ + params + name_len_target;
2012 pSMB->ParameterCount = cpu_to_le16(params);
2013 pSMB->TotalParameterCount = pSMB->ParameterCount;
2014 pSMB->DataCount = cpu_to_le16(name_len_target);
2015 pSMB->TotalDataCount = pSMB->DataCount;
2016 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2017 pSMB->DataOffset = cpu_to_le16(offset);
2018 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2019 pSMB->Reserved4 = 0;
2020 pSMB->hdr.smb_buf_length += byte_count;
2021 pSMB->ByteCount = cpu_to_le16(byte_count);
2022 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2023 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002024 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 if (rc) {
2026 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2027 }
2028
2029 cifs_buf_release(pSMB);
2030 if (rc == -EAGAIN)
2031 goto createHardLinkRetry;
2032
2033 return rc;
2034}
2035
2036int
2037CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2038 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002039 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040{
2041 int rc = 0;
2042 NT_RENAME_REQ *pSMB = NULL;
2043 RENAME_RSP *pSMBr = NULL;
2044 int bytes_returned;
2045 int name_len, name_len2;
2046 __u16 count;
2047
2048 cFYI(1, ("In CIFSCreateHardLink"));
2049winCreateHardLinkRetry:
2050
2051 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2052 (void **) &pSMBr);
2053 if (rc)
2054 return rc;
2055
2056 pSMB->SearchAttributes =
2057 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2058 ATTR_DIRECTORY);
2059 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2060 pSMB->ClusterCount = 0;
2061
2062 pSMB->BufferFormat = 0x04;
2063
2064 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2065 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002066 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002067 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 name_len++; /* trailing null */
2069 name_len *= 2;
2070 pSMB->OldFileName[name_len] = 0; /* pad */
2071 pSMB->OldFileName[name_len + 1] = 0x04;
2072 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002073 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002074 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2076 name_len2 *= 2; /* convert to bytes */
2077 } else { /* BB improve the check for buffer overruns BB */
2078 name_len = strnlen(fromName, PATH_MAX);
2079 name_len++; /* trailing null */
2080 strncpy(pSMB->OldFileName, fromName, name_len);
2081 name_len2 = strnlen(toName, PATH_MAX);
2082 name_len2++; /* trailing null */
2083 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2084 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2085 name_len2++; /* trailing null */
2086 name_len2++; /* signature byte */
2087 }
2088
2089 count = 1 /* string type byte */ + name_len + name_len2;
2090 pSMB->hdr.smb_buf_length += count;
2091 pSMB->ByteCount = cpu_to_le16(count);
2092
2093 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2094 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002095 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 if (rc) {
2097 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2098 }
2099 cifs_buf_release(pSMB);
2100 if (rc == -EAGAIN)
2101 goto winCreateHardLinkRetry;
2102
2103 return rc;
2104}
2105
2106int
2107CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2108 const unsigned char *searchName,
2109 char *symlinkinfo, const int buflen,
2110 const struct nls_table *nls_codepage)
2111{
2112/* SMB_QUERY_FILE_UNIX_LINK */
2113 TRANSACTION2_QPI_REQ *pSMB = NULL;
2114 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2115 int rc = 0;
2116 int bytes_returned;
2117 int name_len;
2118 __u16 params, byte_count;
2119
2120 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2121
2122querySymLinkRetry:
2123 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2124 (void **) &pSMBr);
2125 if (rc)
2126 return rc;
2127
2128 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2129 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002130 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 /* find define for this maxpathcomponent */
2132 , nls_codepage);
2133 name_len++; /* trailing null */
2134 name_len *= 2;
2135 } else { /* BB improve the check for buffer overruns BB */
2136 name_len = strnlen(searchName, PATH_MAX);
2137 name_len++; /* trailing null */
2138 strncpy(pSMB->FileName, searchName, name_len);
2139 }
2140
2141 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2142 pSMB->TotalDataCount = 0;
2143 pSMB->MaxParameterCount = cpu_to_le16(2);
2144 /* BB find exact max data count below from sess structure BB */
2145 pSMB->MaxDataCount = cpu_to_le16(4000);
2146 pSMB->MaxSetupCount = 0;
2147 pSMB->Reserved = 0;
2148 pSMB->Flags = 0;
2149 pSMB->Timeout = 0;
2150 pSMB->Reserved2 = 0;
2151 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2152 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2153 pSMB->DataCount = 0;
2154 pSMB->DataOffset = 0;
2155 pSMB->SetupCount = 1;
2156 pSMB->Reserved3 = 0;
2157 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2158 byte_count = params + 1 /* pad */ ;
2159 pSMB->TotalParameterCount = cpu_to_le16(params);
2160 pSMB->ParameterCount = pSMB->TotalParameterCount;
2161 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2162 pSMB->Reserved4 = 0;
2163 pSMB->hdr.smb_buf_length += byte_count;
2164 pSMB->ByteCount = cpu_to_le16(byte_count);
2165
2166 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2167 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2168 if (rc) {
2169 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2170 } else {
2171 /* decode response */
2172
2173 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2174 if (rc || (pSMBr->ByteCount < 2))
2175 /* BB also check enough total bytes returned */
2176 rc = -EIO; /* bad smb */
2177 else {
2178 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2179 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2180
2181 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2182 name_len = UniStrnlen((wchar_t *) ((char *)
2183 &pSMBr->hdr.Protocol +data_offset),
2184 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002185 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002187 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 data_offset),
2189 name_len, nls_codepage);
2190 } else {
2191 strncpy(symlinkinfo,
2192 (char *) &pSMBr->hdr.Protocol +
2193 data_offset,
2194 min_t(const int, buflen, count));
2195 }
2196 symlinkinfo[buflen] = 0;
2197 /* just in case so calling code does not go off the end of buffer */
2198 }
2199 }
2200 cifs_buf_release(pSMB);
2201 if (rc == -EAGAIN)
2202 goto querySymLinkRetry;
2203 return rc;
2204}
2205
Steve French0a4b92c2006-01-12 15:44:21 -08002206/* Initialize NT TRANSACT SMB into small smb request buffer.
2207 This assumes that all NT TRANSACTS that we init here have
2208 total parm and data under about 400 bytes (to fit in small cifs
2209 buffer size), which is the case so far, it easily fits. NB:
2210 Setup words themselves and ByteCount
2211 MaxSetupCount (size of returned setup area) and
2212 MaxParameterCount (returned parms size) must be set by caller */
2213static int
2214smb_init_ntransact(const __u16 sub_command, const int setup_count,
2215 const int parm_len, struct cifsTconInfo *tcon,
2216 void ** ret_buf)
2217{
2218 int rc;
2219 __u32 temp_offset;
2220 struct smb_com_ntransact_req * pSMB;
2221
2222 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2223 (void **)&pSMB);
2224 if (rc)
2225 return rc;
2226 *ret_buf = (void *)pSMB;
2227 pSMB->Reserved = 0;
2228 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2229 pSMB->TotalDataCount = 0;
2230 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2231 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2232 pSMB->ParameterCount = pSMB->TotalParameterCount;
2233 pSMB->DataCount = pSMB->TotalDataCount;
2234 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2235 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2236 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2237 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2238 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2239 pSMB->SubCommand = cpu_to_le16(sub_command);
2240 return 0;
2241}
2242
2243static int
2244validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2245 int * pdatalen, int * pparmlen)
2246{
2247 char * end_of_smb;
2248 __u32 data_count, data_offset, parm_count, parm_offset;
2249 struct smb_com_ntransact_rsp * pSMBr;
2250
2251 if(buf == NULL)
2252 return -EINVAL;
2253
2254 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2255
2256 /* ByteCount was converted from little endian in SendReceive */
2257 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2258 (char *)&pSMBr->ByteCount;
2259
2260
2261 data_offset = le32_to_cpu(pSMBr->DataOffset);
2262 data_count = le32_to_cpu(pSMBr->DataCount);
2263 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2264 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2265
2266 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2267 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2268
2269 /* should we also check that parm and data areas do not overlap? */
2270 if(*ppparm > end_of_smb) {
2271 cFYI(1,("parms start after end of smb"));
2272 return -EINVAL;
2273 } else if(parm_count + *ppparm > end_of_smb) {
2274 cFYI(1,("parm end after end of smb"));
2275 return -EINVAL;
2276 } else if(*ppdata > end_of_smb) {
2277 cFYI(1,("data starts after end of smb"));
2278 return -EINVAL;
2279 } else if(data_count + *ppdata > end_of_smb) {
2280 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2281 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2282 return -EINVAL;
2283 } else if(parm_count + data_count > pSMBr->ByteCount) {
2284 cFYI(1,("parm count and data count larger than SMB"));
2285 return -EINVAL;
2286 }
2287 return 0;
2288}
2289
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290int
2291CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2292 const unsigned char *searchName,
2293 char *symlinkinfo, const int buflen,__u16 fid,
2294 const struct nls_table *nls_codepage)
2295{
2296 int rc = 0;
2297 int bytes_returned;
2298 int name_len;
2299 struct smb_com_transaction_ioctl_req * pSMB;
2300 struct smb_com_transaction_ioctl_rsp * pSMBr;
2301
2302 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2303 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2304 (void **) &pSMBr);
2305 if (rc)
2306 return rc;
2307
2308 pSMB->TotalParameterCount = 0 ;
2309 pSMB->TotalDataCount = 0;
2310 pSMB->MaxParameterCount = cpu_to_le32(2);
2311 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002312 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2313 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 pSMB->MaxSetupCount = 4;
2315 pSMB->Reserved = 0;
2316 pSMB->ParameterOffset = 0;
2317 pSMB->DataCount = 0;
2318 pSMB->DataOffset = 0;
2319 pSMB->SetupCount = 4;
2320 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2321 pSMB->ParameterCount = pSMB->TotalParameterCount;
2322 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2323 pSMB->IsFsctl = 1; /* FSCTL */
2324 pSMB->IsRootFlag = 0;
2325 pSMB->Fid = fid; /* file handle always le */
2326 pSMB->ByteCount = 0;
2327
2328 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2329 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2330 if (rc) {
2331 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2332 } else { /* decode response */
2333 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2334 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2335 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2336 /* BB also check enough total bytes returned */
2337 rc = -EIO; /* bad smb */
2338 else {
2339 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002340 char * end_of_smb = 2 /* sizeof byte count */ +
2341 pSMBr->ByteCount +
2342 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343
2344 struct reparse_data * reparse_buf = (struct reparse_data *)
2345 ((char *)&pSMBr->hdr.Protocol + data_offset);
2346 if((char*)reparse_buf >= end_of_smb) {
2347 rc = -EIO;
2348 goto qreparse_out;
2349 }
2350 if((reparse_buf->LinkNamesBuf +
2351 reparse_buf->TargetNameOffset +
2352 reparse_buf->TargetNameLen) >
2353 end_of_smb) {
2354 cFYI(1,("reparse buf extended beyond SMB"));
2355 rc = -EIO;
2356 goto qreparse_out;
2357 }
2358
2359 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2360 name_len = UniStrnlen((wchar_t *)
2361 (reparse_buf->LinkNamesBuf +
2362 reparse_buf->TargetNameOffset),
2363 min(buflen/2, reparse_buf->TargetNameLen / 2));
2364 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002365 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 reparse_buf->TargetNameOffset),
2367 name_len, nls_codepage);
2368 } else { /* ASCII names */
2369 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2370 reparse_buf->TargetNameOffset,
2371 min_t(const int, buflen, reparse_buf->TargetNameLen));
2372 }
2373 } else {
2374 rc = -EIO;
2375 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2376 }
2377 symlinkinfo[buflen] = 0; /* just in case so the caller
2378 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002379 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 }
2381 }
2382qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002383 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384
2385 /* Note: On -EAGAIN error only caller can retry on handle based calls
2386 since file handle passed in no longer valid */
2387
2388 return rc;
2389}
2390
2391#ifdef CONFIG_CIFS_POSIX
2392
2393/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2394static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2395{
2396 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002397 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2398 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2399 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2401
2402 return;
2403}
2404
2405/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002406static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2407 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408{
2409 int size = 0;
2410 int i;
2411 __u16 count;
2412 struct cifs_posix_ace * pACE;
2413 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2414 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2415
2416 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2417 return -EOPNOTSUPP;
2418
2419 if(acl_type & ACL_TYPE_ACCESS) {
2420 count = le16_to_cpu(cifs_acl->access_entry_count);
2421 pACE = &cifs_acl->ace_array[0];
2422 size = sizeof(struct cifs_posix_acl);
2423 size += sizeof(struct cifs_posix_ace) * count;
2424 /* check if we would go beyond end of SMB */
2425 if(size_of_data_area < size) {
2426 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2427 return -EINVAL;
2428 }
2429 } else if(acl_type & ACL_TYPE_DEFAULT) {
2430 count = le16_to_cpu(cifs_acl->access_entry_count);
2431 size = sizeof(struct cifs_posix_acl);
2432 size += sizeof(struct cifs_posix_ace) * count;
2433/* skip past access ACEs to get to default ACEs */
2434 pACE = &cifs_acl->ace_array[count];
2435 count = le16_to_cpu(cifs_acl->default_entry_count);
2436 size += sizeof(struct cifs_posix_ace) * count;
2437 /* check if we would go beyond end of SMB */
2438 if(size_of_data_area < size)
2439 return -EINVAL;
2440 } else {
2441 /* illegal type */
2442 return -EINVAL;
2443 }
2444
2445 size = posix_acl_xattr_size(count);
2446 if((buflen == 0) || (local_acl == NULL)) {
2447 /* used to query ACL EA size */
2448 } else if(size > buflen) {
2449 return -ERANGE;
2450 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002451 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 for(i = 0;i < count ;i++) {
2453 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2454 pACE ++;
2455 }
2456 }
2457 return size;
2458}
2459
2460static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2461 const posix_acl_xattr_entry * local_ace)
2462{
2463 __u16 rc = 0; /* 0 = ACL converted ok */
2464
Steve Frenchff7feac2005-11-15 16:45:16 -08002465 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2466 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002468 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 /* Probably no need to le convert -1 on any arch but can not hurt */
2470 cifs_ace->cifs_uid = cpu_to_le64(-1);
2471 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002472 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2474 return rc;
2475}
2476
2477/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2478static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2479 const int acl_type)
2480{
2481 __u16 rc = 0;
2482 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2483 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2484 int count;
2485 int i;
2486
2487 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2488 return 0;
2489
2490 count = posix_acl_xattr_count((size_t)buflen);
2491 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002492 count, buflen, le32_to_cpu(local_acl->a_version)));
2493 if(le32_to_cpu(local_acl->a_version) != 2) {
2494 cFYI(1,("unknown POSIX ACL version %d",
2495 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 return 0;
2497 }
2498 cifs_acl->version = cpu_to_le16(1);
2499 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002500 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002502 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 else {
2504 cFYI(1,("unknown ACL type %d",acl_type));
2505 return 0;
2506 }
2507 for(i=0;i<count;i++) {
2508 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2509 &local_acl->a_entries[i]);
2510 if(rc != 0) {
2511 /* ACE not converted */
2512 break;
2513 }
2514 }
2515 if(rc == 0) {
2516 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2517 rc += sizeof(struct cifs_posix_acl);
2518 /* BB add check to make sure ACL does not overflow SMB */
2519 }
2520 return rc;
2521}
2522
2523int
2524CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2525 const unsigned char *searchName,
2526 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002527 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528{
2529/* SMB_QUERY_POSIX_ACL */
2530 TRANSACTION2_QPI_REQ *pSMB = NULL;
2531 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2532 int rc = 0;
2533 int bytes_returned;
2534 int name_len;
2535 __u16 params, byte_count;
2536
2537 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2538
2539queryAclRetry:
2540 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2541 (void **) &pSMBr);
2542 if (rc)
2543 return rc;
2544
2545 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2546 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002547 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002548 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 name_len++; /* trailing null */
2550 name_len *= 2;
2551 pSMB->FileName[name_len] = 0;
2552 pSMB->FileName[name_len+1] = 0;
2553 } else { /* BB improve the check for buffer overruns BB */
2554 name_len = strnlen(searchName, PATH_MAX);
2555 name_len++; /* trailing null */
2556 strncpy(pSMB->FileName, searchName, name_len);
2557 }
2558
2559 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2560 pSMB->TotalDataCount = 0;
2561 pSMB->MaxParameterCount = cpu_to_le16(2);
2562 /* BB find exact max data count below from sess structure BB */
2563 pSMB->MaxDataCount = cpu_to_le16(4000);
2564 pSMB->MaxSetupCount = 0;
2565 pSMB->Reserved = 0;
2566 pSMB->Flags = 0;
2567 pSMB->Timeout = 0;
2568 pSMB->Reserved2 = 0;
2569 pSMB->ParameterOffset = cpu_to_le16(
2570 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2571 pSMB->DataCount = 0;
2572 pSMB->DataOffset = 0;
2573 pSMB->SetupCount = 1;
2574 pSMB->Reserved3 = 0;
2575 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2576 byte_count = params + 1 /* pad */ ;
2577 pSMB->TotalParameterCount = cpu_to_le16(params);
2578 pSMB->ParameterCount = pSMB->TotalParameterCount;
2579 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2580 pSMB->Reserved4 = 0;
2581 pSMB->hdr.smb_buf_length += byte_count;
2582 pSMB->ByteCount = cpu_to_le16(byte_count);
2583
2584 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2585 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002586 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 if (rc) {
2588 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2589 } else {
2590 /* decode response */
2591
2592 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2593 if (rc || (pSMBr->ByteCount < 2))
2594 /* BB also check enough total bytes returned */
2595 rc = -EIO; /* bad smb */
2596 else {
2597 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2598 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2599 rc = cifs_copy_posix_acl(acl_inf,
2600 (char *)&pSMBr->hdr.Protocol+data_offset,
2601 buflen,acl_type,count);
2602 }
2603 }
2604 cifs_buf_release(pSMB);
2605 if (rc == -EAGAIN)
2606 goto queryAclRetry;
2607 return rc;
2608}
2609
2610int
2611CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2612 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002613 const char *local_acl, const int buflen,
2614 const int acl_type,
2615 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616{
2617 struct smb_com_transaction2_spi_req *pSMB = NULL;
2618 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2619 char *parm_data;
2620 int name_len;
2621 int rc = 0;
2622 int bytes_returned = 0;
2623 __u16 params, byte_count, data_count, param_offset, offset;
2624
2625 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2626setAclRetry:
2627 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2628 (void **) &pSMBr);
2629 if (rc)
2630 return rc;
2631 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2632 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002633 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002634 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 name_len++; /* trailing null */
2636 name_len *= 2;
2637 } else { /* BB improve the check for buffer overruns BB */
2638 name_len = strnlen(fileName, PATH_MAX);
2639 name_len++; /* trailing null */
2640 strncpy(pSMB->FileName, fileName, name_len);
2641 }
2642 params = 6 + name_len;
2643 pSMB->MaxParameterCount = cpu_to_le16(2);
2644 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2645 pSMB->MaxSetupCount = 0;
2646 pSMB->Reserved = 0;
2647 pSMB->Flags = 0;
2648 pSMB->Timeout = 0;
2649 pSMB->Reserved2 = 0;
2650 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2651 InformationLevel) - 4;
2652 offset = param_offset + params;
2653 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2654 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2655
2656 /* convert to on the wire format for POSIX ACL */
2657 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2658
2659 if(data_count == 0) {
2660 rc = -EOPNOTSUPP;
2661 goto setACLerrorExit;
2662 }
2663 pSMB->DataOffset = cpu_to_le16(offset);
2664 pSMB->SetupCount = 1;
2665 pSMB->Reserved3 = 0;
2666 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2667 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2668 byte_count = 3 /* pad */ + params + data_count;
2669 pSMB->DataCount = cpu_to_le16(data_count);
2670 pSMB->TotalDataCount = pSMB->DataCount;
2671 pSMB->ParameterCount = cpu_to_le16(params);
2672 pSMB->TotalParameterCount = pSMB->ParameterCount;
2673 pSMB->Reserved4 = 0;
2674 pSMB->hdr.smb_buf_length += byte_count;
2675 pSMB->ByteCount = cpu_to_le16(byte_count);
2676 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2677 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2678 if (rc) {
2679 cFYI(1, ("Set POSIX ACL returned %d", rc));
2680 }
2681
2682setACLerrorExit:
2683 cifs_buf_release(pSMB);
2684 if (rc == -EAGAIN)
2685 goto setAclRetry;
2686 return rc;
2687}
2688
Steve Frenchf654bac2005-04-28 22:41:04 -07002689/* BB fix tabs in this function FIXME BB */
2690int
2691CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2692 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2693{
2694 int rc = 0;
2695 struct smb_t2_qfi_req *pSMB = NULL;
2696 struct smb_t2_qfi_rsp *pSMBr = NULL;
2697 int bytes_returned;
2698 __u16 params, byte_count;
2699
2700 cFYI(1,("In GetExtAttr"));
2701 if(tcon == NULL)
2702 return -ENODEV;
2703
2704GetExtAttrRetry:
2705 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2706 (void **) &pSMBr);
2707 if (rc)
2708 return rc;
2709
Steve Frenchc67593a2005-04-28 22:41:04 -07002710 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002711 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002712 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002713 /* BB find exact max data count below from sess structure BB */
2714 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2715 pSMB->t2.MaxSetupCount = 0;
2716 pSMB->t2.Reserved = 0;
2717 pSMB->t2.Flags = 0;
2718 pSMB->t2.Timeout = 0;
2719 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002720 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2721 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002722 pSMB->t2.DataCount = 0;
2723 pSMB->t2.DataOffset = 0;
2724 pSMB->t2.SetupCount = 1;
2725 pSMB->t2.Reserved3 = 0;
2726 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002727 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002728 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2729 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2730 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002731 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002732 pSMB->Fid = netfid;
2733 pSMB->hdr.smb_buf_length += byte_count;
2734 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2735
2736 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2737 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2738 if (rc) {
2739 cFYI(1, ("error %d in GetExtAttr", rc));
2740 } else {
2741 /* decode response */
2742 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2743 if (rc || (pSMBr->ByteCount < 2))
2744 /* BB also check enough total bytes returned */
2745 /* If rc should we check for EOPNOSUPP and
2746 disable the srvino flag? or in caller? */
2747 rc = -EIO; /* bad smb */
2748 else {
2749 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2750 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2751 struct file_chattr_info * pfinfo;
2752 /* BB Do we need a cast or hash here ? */
2753 if(count != 16) {
2754 cFYI(1, ("Illegal size ret in GetExtAttr"));
2755 rc = -EIO;
2756 goto GetExtAttrOut;
2757 }
2758 pfinfo = (struct file_chattr_info *)
2759 (data_offset + (char *) &pSMBr->hdr.Protocol);
2760 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2761 *pMask = le64_to_cpu(pfinfo->mask);
2762 }
2763 }
2764GetExtAttrOut:
2765 cifs_buf_release(pSMB);
2766 if (rc == -EAGAIN)
2767 goto GetExtAttrRetry;
2768 return rc;
2769}
2770
2771
2772#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773
Steve Frencheeac8042006-01-13 21:34:58 -08002774
2775/* security id for everyone */
2776const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2777/* group users */
2778const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2779
Steve French0a4b92c2006-01-12 15:44:21 -08002780/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002781static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002782{
Steve French0a4b92c2006-01-12 15:44:21 -08002783 return 0;
2784}
2785
2786/* Get Security Descriptor (by handle) from remote server for a file or dir */
2787int
2788CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2789 /* BB fix up return info */ char *acl_inf, const int buflen,
2790 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2791{
2792 int rc = 0;
2793 int buf_type = 0;
2794 QUERY_SEC_DESC_REQ * pSMB;
2795 struct kvec iov[1];
2796
2797 cFYI(1, ("GetCifsACL"));
2798
2799 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2800 8 /* parm len */, tcon, (void **) &pSMB);
2801 if (rc)
2802 return rc;
2803
2804 pSMB->MaxParameterCount = cpu_to_le32(4);
2805 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2806 pSMB->MaxSetupCount = 0;
2807 pSMB->Fid = fid; /* file handle always le */
2808 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2809 CIFS_ACL_DACL);
2810 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2811 pSMB->hdr.smb_buf_length += 11;
2812 iov[0].iov_base = (char *)pSMB;
2813 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2814
2815 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2816 cifs_stats_inc(&tcon->num_acl_get);
2817 if (rc) {
2818 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2819 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002820 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002821 __le32 * parm;
2822 int parm_len;
2823 int data_len;
2824 int acl_len;
2825 struct smb_com_ntransact_rsp * pSMBr;
2826
2827/* validate_nttransact */
2828 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2829 (char **)&psec_desc,
2830 &parm_len, &data_len);
2831
2832 if(rc)
2833 goto qsec_out;
2834 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2835
2836 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2837
2838 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2839 rc = -EIO; /* bad smb */
2840 goto qsec_out;
2841 }
2842
2843/* BB check that data area is minimum length and as big as acl_len */
2844
2845 acl_len = le32_to_cpu(*(__le32 *)parm);
2846 /* BB check if(acl_len > bufsize) */
2847
2848 parse_sec_desc(psec_desc, acl_len);
2849 }
2850qsec_out:
2851 if(buf_type == CIFS_SMALL_BUFFER)
2852 cifs_small_buf_release(iov[0].iov_base);
2853 else if(buf_type == CIFS_LARGE_BUFFER)
2854 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002855/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002856 return rc;
2857}
2858
Steve French6b8edfe2005-08-23 20:26:03 -07002859/* Legacy Query Path Information call for lookup to old servers such
2860 as Win9x/WinME */
2861int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2862 const unsigned char *searchName,
2863 FILE_ALL_INFO * pFinfo,
2864 const struct nls_table *nls_codepage, int remap)
2865{
2866 QUERY_INFORMATION_REQ * pSMB;
2867 QUERY_INFORMATION_RSP * pSMBr;
2868 int rc = 0;
2869 int bytes_returned;
2870 int name_len;
2871
2872 cFYI(1, ("In SMBQPath path %s", searchName));
2873QInfRetry:
2874 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2875 (void **) &pSMBr);
2876 if (rc)
2877 return rc;
2878
2879 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2880 name_len =
2881 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2882 PATH_MAX, nls_codepage, remap);
2883 name_len++; /* trailing null */
2884 name_len *= 2;
2885 } else {
2886 name_len = strnlen(searchName, PATH_MAX);
2887 name_len++; /* trailing null */
2888 strncpy(pSMB->FileName, searchName, name_len);
2889 }
2890 pSMB->BufferFormat = 0x04;
2891 name_len++; /* account for buffer type byte */
2892 pSMB->hdr.smb_buf_length += (__u16) name_len;
2893 pSMB->ByteCount = cpu_to_le16(name_len);
2894
2895 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2896 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2897 if (rc) {
2898 cFYI(1, ("Send error in QueryInfo = %d", rc));
2899 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00002900 struct timespec ts;
2901 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2902 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07002903 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00002904 ts.tv_nsec = 0;
2905 ts.tv_sec = time;
2906 /* decode time fields */
2907 pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
2908 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2909 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07002910 pFinfo->AllocationSize =
2911 cpu_to_le64(le32_to_cpu(pSMBr->size));
2912 pFinfo->EndOfFile = pFinfo->AllocationSize;
2913 pFinfo->Attributes =
2914 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002915 } else
2916 rc = -EIO; /* bad buffer passed in */
2917
2918 cifs_buf_release(pSMB);
2919
2920 if (rc == -EAGAIN)
2921 goto QInfRetry;
2922
2923 return rc;
2924}
2925
2926
2927
2928
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929int
2930CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2931 const unsigned char *searchName,
2932 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002933 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934{
2935/* level 263 SMB_QUERY_FILE_ALL_INFO */
2936 TRANSACTION2_QPI_REQ *pSMB = NULL;
2937 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2938 int rc = 0;
2939 int bytes_returned;
2940 int name_len;
2941 __u16 params, byte_count;
2942
2943/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2944QPathInfoRetry:
2945 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2946 (void **) &pSMBr);
2947 if (rc)
2948 return rc;
2949
2950 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2951 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002952 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002953 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 name_len++; /* trailing null */
2955 name_len *= 2;
2956 } else { /* BB improve the check for buffer overruns BB */
2957 name_len = strnlen(searchName, PATH_MAX);
2958 name_len++; /* trailing null */
2959 strncpy(pSMB->FileName, searchName, name_len);
2960 }
2961
2962 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2963 pSMB->TotalDataCount = 0;
2964 pSMB->MaxParameterCount = cpu_to_le16(2);
2965 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2966 pSMB->MaxSetupCount = 0;
2967 pSMB->Reserved = 0;
2968 pSMB->Flags = 0;
2969 pSMB->Timeout = 0;
2970 pSMB->Reserved2 = 0;
2971 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2972 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2973 pSMB->DataCount = 0;
2974 pSMB->DataOffset = 0;
2975 pSMB->SetupCount = 1;
2976 pSMB->Reserved3 = 0;
2977 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2978 byte_count = params + 1 /* pad */ ;
2979 pSMB->TotalParameterCount = cpu_to_le16(params);
2980 pSMB->ParameterCount = pSMB->TotalParameterCount;
2981 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2982 pSMB->Reserved4 = 0;
2983 pSMB->hdr.smb_buf_length += byte_count;
2984 pSMB->ByteCount = cpu_to_le16(byte_count);
2985
2986 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2987 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2988 if (rc) {
2989 cFYI(1, ("Send error in QPathInfo = %d", rc));
2990 } else { /* decode response */
2991 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2992
2993 if (rc || (pSMBr->ByteCount < 40))
2994 rc = -EIO; /* bad smb */
2995 else if (pFindData){
2996 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2997 memcpy((char *) pFindData,
2998 (char *) &pSMBr->hdr.Protocol +
2999 data_offset, sizeof (FILE_ALL_INFO));
3000 } else
3001 rc = -ENOMEM;
3002 }
3003 cifs_buf_release(pSMB);
3004 if (rc == -EAGAIN)
3005 goto QPathInfoRetry;
3006
3007 return rc;
3008}
3009
3010int
3011CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3012 const unsigned char *searchName,
3013 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003014 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015{
3016/* SMB_QUERY_FILE_UNIX_BASIC */
3017 TRANSACTION2_QPI_REQ *pSMB = NULL;
3018 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3019 int rc = 0;
3020 int bytes_returned = 0;
3021 int name_len;
3022 __u16 params, byte_count;
3023
3024 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3025UnixQPathInfoRetry:
3026 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3027 (void **) &pSMBr);
3028 if (rc)
3029 return rc;
3030
3031 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3032 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003033 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003034 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 name_len++; /* trailing null */
3036 name_len *= 2;
3037 } else { /* BB improve the check for buffer overruns BB */
3038 name_len = strnlen(searchName, PATH_MAX);
3039 name_len++; /* trailing null */
3040 strncpy(pSMB->FileName, searchName, name_len);
3041 }
3042
3043 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3044 pSMB->TotalDataCount = 0;
3045 pSMB->MaxParameterCount = cpu_to_le16(2);
3046 /* BB find exact max SMB PDU from sess structure BB */
3047 pSMB->MaxDataCount = cpu_to_le16(4000);
3048 pSMB->MaxSetupCount = 0;
3049 pSMB->Reserved = 0;
3050 pSMB->Flags = 0;
3051 pSMB->Timeout = 0;
3052 pSMB->Reserved2 = 0;
3053 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3054 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3055 pSMB->DataCount = 0;
3056 pSMB->DataOffset = 0;
3057 pSMB->SetupCount = 1;
3058 pSMB->Reserved3 = 0;
3059 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3060 byte_count = params + 1 /* pad */ ;
3061 pSMB->TotalParameterCount = cpu_to_le16(params);
3062 pSMB->ParameterCount = pSMB->TotalParameterCount;
3063 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3064 pSMB->Reserved4 = 0;
3065 pSMB->hdr.smb_buf_length += byte_count;
3066 pSMB->ByteCount = cpu_to_le16(byte_count);
3067
3068 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3070 if (rc) {
3071 cFYI(1, ("Send error in QPathInfo = %d", rc));
3072 } else { /* decode response */
3073 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3074
3075 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3076 rc = -EIO; /* bad smb */
3077 } else {
3078 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3079 memcpy((char *) pFindData,
3080 (char *) &pSMBr->hdr.Protocol +
3081 data_offset,
3082 sizeof (FILE_UNIX_BASIC_INFO));
3083 }
3084 }
3085 cifs_buf_release(pSMB);
3086 if (rc == -EAGAIN)
3087 goto UnixQPathInfoRetry;
3088
3089 return rc;
3090}
3091
3092#if 0 /* function unused at present */
3093int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3094 const char *searchName, FILE_ALL_INFO * findData,
3095 const struct nls_table *nls_codepage)
3096{
3097/* level 257 SMB_ */
3098 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3099 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3100 int rc = 0;
3101 int bytes_returned;
3102 int name_len;
3103 __u16 params, byte_count;
3104
3105 cFYI(1, ("In FindUnique"));
3106findUniqueRetry:
3107 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3108 (void **) &pSMBr);
3109 if (rc)
3110 return rc;
3111
3112 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3113 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003114 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 /* find define for this maxpathcomponent */
3116 , nls_codepage);
3117 name_len++; /* trailing null */
3118 name_len *= 2;
3119 } else { /* BB improve the check for buffer overruns BB */
3120 name_len = strnlen(searchName, PATH_MAX);
3121 name_len++; /* trailing null */
3122 strncpy(pSMB->FileName, searchName, name_len);
3123 }
3124
3125 params = 12 + name_len /* includes null */ ;
3126 pSMB->TotalDataCount = 0; /* no EAs */
3127 pSMB->MaxParameterCount = cpu_to_le16(2);
3128 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3129 pSMB->MaxSetupCount = 0;
3130 pSMB->Reserved = 0;
3131 pSMB->Flags = 0;
3132 pSMB->Timeout = 0;
3133 pSMB->Reserved2 = 0;
3134 pSMB->ParameterOffset = cpu_to_le16(
3135 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3136 pSMB->DataCount = 0;
3137 pSMB->DataOffset = 0;
3138 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3139 pSMB->Reserved3 = 0;
3140 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3141 byte_count = params + 1 /* pad */ ;
3142 pSMB->TotalParameterCount = cpu_to_le16(params);
3143 pSMB->ParameterCount = pSMB->TotalParameterCount;
3144 pSMB->SearchAttributes =
3145 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3146 ATTR_DIRECTORY);
3147 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3148 pSMB->SearchFlags = cpu_to_le16(1);
3149 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3150 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3151 pSMB->hdr.smb_buf_length += byte_count;
3152 pSMB->ByteCount = cpu_to_le16(byte_count);
3153
3154 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3155 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3156
3157 if (rc) {
3158 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3159 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003160 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 /* BB fill in */
3162 }
3163
3164 cifs_buf_release(pSMB);
3165 if (rc == -EAGAIN)
3166 goto findUniqueRetry;
3167
3168 return rc;
3169}
3170#endif /* end unused (temporarily) function */
3171
3172/* xid, tcon, searchName and codepage are input parms, rest are returned */
3173int
3174CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3175 const char *searchName,
3176 const struct nls_table *nls_codepage,
3177 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003178 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179{
3180/* level 257 SMB_ */
3181 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3182 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3183 T2_FFIRST_RSP_PARMS * parms;
3184 int rc = 0;
3185 int bytes_returned = 0;
3186 int name_len;
3187 __u16 params, byte_count;
3188
Steve French737b7582005-04-28 22:41:06 -07003189 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190
3191findFirstRetry:
3192 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3193 (void **) &pSMBr);
3194 if (rc)
3195 return rc;
3196
3197 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3198 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003199 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003200 PATH_MAX, nls_codepage, remap);
3201 /* We can not add the asterik earlier in case
3202 it got remapped to 0xF03A as if it were part of the
3203 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003205 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003206 pSMB->FileName[name_len+1] = 0;
3207 pSMB->FileName[name_len+2] = '*';
3208 pSMB->FileName[name_len+3] = 0;
3209 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3211 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003212 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 } else { /* BB add check for overrun of SMB buf BB */
3214 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215/* BB fix here and in unicode clause above ie
3216 if(name_len > buffersize-header)
3217 free buffer exit; BB */
3218 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003219 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003220 pSMB->FileName[name_len+1] = '*';
3221 pSMB->FileName[name_len+2] = 0;
3222 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 }
3224
3225 params = 12 + name_len /* includes null */ ;
3226 pSMB->TotalDataCount = 0; /* no EAs */
3227 pSMB->MaxParameterCount = cpu_to_le16(10);
3228 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3229 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3230 pSMB->MaxSetupCount = 0;
3231 pSMB->Reserved = 0;
3232 pSMB->Flags = 0;
3233 pSMB->Timeout = 0;
3234 pSMB->Reserved2 = 0;
3235 byte_count = params + 1 /* pad */ ;
3236 pSMB->TotalParameterCount = cpu_to_le16(params);
3237 pSMB->ParameterCount = pSMB->TotalParameterCount;
3238 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003239 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3240 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 pSMB->DataCount = 0;
3242 pSMB->DataOffset = 0;
3243 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3244 pSMB->Reserved3 = 0;
3245 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3246 pSMB->SearchAttributes =
3247 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3248 ATTR_DIRECTORY);
3249 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3250 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3251 CIFS_SEARCH_RETURN_RESUME);
3252 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3253
3254 /* BB what should we set StorageType to? Does it matter? BB */
3255 pSMB->SearchStorageType = 0;
3256 pSMB->hdr.smb_buf_length += byte_count;
3257 pSMB->ByteCount = cpu_to_le16(byte_count);
3258
3259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3260 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003261 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262
Steve French88274812006-03-09 22:21:45 +00003263 if (rc) {/* BB add logic to retry regular search if Unix search
3264 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 /* BB Add code to handle unsupported level rc */
3266 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003267
Steve French88274812006-03-09 22:21:45 +00003268 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269
3270 /* BB eventually could optimize out free and realloc of buf */
3271 /* for this case */
3272 if (rc == -EAGAIN)
3273 goto findFirstRetry;
3274 } else { /* decode response */
3275 /* BB remember to free buffer if error BB */
3276 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3277 if(rc == 0) {
3278 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3279 psrch_inf->unicode = TRUE;
3280 else
3281 psrch_inf->unicode = FALSE;
3282
3283 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003284 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 psrch_inf->srch_entries_start =
3286 (char *) &pSMBr->hdr.Protocol +
3287 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3289 le16_to_cpu(pSMBr->t2.ParameterOffset));
3290
3291 if(parms->EndofSearch)
3292 psrch_inf->endOfSearch = TRUE;
3293 else
3294 psrch_inf->endOfSearch = FALSE;
3295
3296 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003297 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 *pnetfid = parms->SearchHandle;
3300 } else {
3301 cifs_buf_release(pSMB);
3302 }
3303 }
3304
3305 return rc;
3306}
3307
3308int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3309 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3310{
3311 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3312 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3313 T2_FNEXT_RSP_PARMS * parms;
3314 char *response_data;
3315 int rc = 0;
3316 int bytes_returned, name_len;
3317 __u16 params, byte_count;
3318
3319 cFYI(1, ("In FindNext"));
3320
3321 if(psrch_inf->endOfSearch == TRUE)
3322 return -ENOENT;
3323
3324 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3325 (void **) &pSMBr);
3326 if (rc)
3327 return rc;
3328
3329 params = 14; /* includes 2 bytes of null string, converted to LE below */
3330 byte_count = 0;
3331 pSMB->TotalDataCount = 0; /* no EAs */
3332 pSMB->MaxParameterCount = cpu_to_le16(8);
3333 pSMB->MaxDataCount =
3334 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3335 pSMB->MaxSetupCount = 0;
3336 pSMB->Reserved = 0;
3337 pSMB->Flags = 0;
3338 pSMB->Timeout = 0;
3339 pSMB->Reserved2 = 0;
3340 pSMB->ParameterOffset = cpu_to_le16(
3341 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3342 pSMB->DataCount = 0;
3343 pSMB->DataOffset = 0;
3344 pSMB->SetupCount = 1;
3345 pSMB->Reserved3 = 0;
3346 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3347 pSMB->SearchHandle = searchHandle; /* always kept as le */
3348 pSMB->SearchCount =
3349 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3350 /* test for Unix extensions */
3351/* if (tcon->ses->capabilities & CAP_UNIX) {
3352 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3353 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3354 } else {
3355 pSMB->InformationLevel =
3356 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3357 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3358 } */
3359 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3360 pSMB->ResumeKey = psrch_inf->resume_key;
3361 pSMB->SearchFlags =
3362 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3363
3364 name_len = psrch_inf->resume_name_len;
3365 params += name_len;
3366 if(name_len < PATH_MAX) {
3367 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3368 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003369 /* 14 byte parm len above enough for 2 byte null terminator */
3370 pSMB->ResumeFileName[name_len] = 0;
3371 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 } else {
3373 rc = -EINVAL;
3374 goto FNext2_err_exit;
3375 }
3376 byte_count = params + 1 /* pad */ ;
3377 pSMB->TotalParameterCount = cpu_to_le16(params);
3378 pSMB->ParameterCount = pSMB->TotalParameterCount;
3379 pSMB->hdr.smb_buf_length += byte_count;
3380 pSMB->ByteCount = cpu_to_le16(byte_count);
3381
3382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3383 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003384 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 if (rc) {
3386 if (rc == -EBADF) {
3387 psrch_inf->endOfSearch = TRUE;
3388 rc = 0; /* search probably was closed at end of search above */
3389 } else
3390 cFYI(1, ("FindNext returned = %d", rc));
3391 } else { /* decode response */
3392 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3393
3394 if(rc == 0) {
3395 /* BB fixme add lock for file (srch_info) struct here */
3396 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3397 psrch_inf->unicode = TRUE;
3398 else
3399 psrch_inf->unicode = FALSE;
3400 response_data = (char *) &pSMBr->hdr.Protocol +
3401 le16_to_cpu(pSMBr->t2.ParameterOffset);
3402 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3403 response_data = (char *)&pSMBr->hdr.Protocol +
3404 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003405 if(psrch_inf->smallBuf)
3406 cifs_small_buf_release(
3407 psrch_inf->ntwrk_buf_start);
3408 else
3409 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 psrch_inf->srch_entries_start = response_data;
3411 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003412 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 if(parms->EndofSearch)
3414 psrch_inf->endOfSearch = TRUE;
3415 else
3416 psrch_inf->endOfSearch = FALSE;
3417
3418 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3419 psrch_inf->index_of_last_entry +=
3420 psrch_inf->entries_in_buffer;
3421/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3422
3423 /* BB fixme add unlock here */
3424 }
3425
3426 }
3427
3428 /* BB On error, should we leave previous search buf (and count and
3429 last entry fields) intact or free the previous one? */
3430
3431 /* Note: On -EAGAIN error only caller can retry on handle based calls
3432 since file handle passed in no longer valid */
3433FNext2_err_exit:
3434 if (rc != 0)
3435 cifs_buf_release(pSMB);
3436
3437 return rc;
3438}
3439
3440int
3441CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3442{
3443 int rc = 0;
3444 FINDCLOSE_REQ *pSMB = NULL;
3445 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3446 int bytes_returned;
3447
3448 cFYI(1, ("In CIFSSMBFindClose"));
3449 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3450
3451 /* no sense returning error if session restarted
3452 as file handle has been closed */
3453 if(rc == -EAGAIN)
3454 return 0;
3455 if (rc)
3456 return rc;
3457
3458 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3459 pSMB->FileID = searchHandle;
3460 pSMB->ByteCount = 0;
3461 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3462 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3463 if (rc) {
3464 cERROR(1, ("Send error in FindClose = %d", rc));
3465 }
Steve Frencha4544342005-08-24 13:59:35 -07003466 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 cifs_small_buf_release(pSMB);
3468
3469 /* Since session is dead, search handle closed on server already */
3470 if (rc == -EAGAIN)
3471 rc = 0;
3472
3473 return rc;
3474}
3475
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476int
3477CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3478 const unsigned char *searchName,
3479 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003480 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481{
3482 int rc = 0;
3483 TRANSACTION2_QPI_REQ *pSMB = NULL;
3484 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3485 int name_len, bytes_returned;
3486 __u16 params, byte_count;
3487
3488 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3489 if(tcon == NULL)
3490 return -ENODEV;
3491
3492GetInodeNumberRetry:
3493 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3494 (void **) &pSMBr);
3495 if (rc)
3496 return rc;
3497
3498
3499 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3500 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003501 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003502 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 name_len++; /* trailing null */
3504 name_len *= 2;
3505 } else { /* BB improve the check for buffer overruns BB */
3506 name_len = strnlen(searchName, PATH_MAX);
3507 name_len++; /* trailing null */
3508 strncpy(pSMB->FileName, searchName, name_len);
3509 }
3510
3511 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3512 pSMB->TotalDataCount = 0;
3513 pSMB->MaxParameterCount = cpu_to_le16(2);
3514 /* BB find exact max data count below from sess structure BB */
3515 pSMB->MaxDataCount = cpu_to_le16(4000);
3516 pSMB->MaxSetupCount = 0;
3517 pSMB->Reserved = 0;
3518 pSMB->Flags = 0;
3519 pSMB->Timeout = 0;
3520 pSMB->Reserved2 = 0;
3521 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3522 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3523 pSMB->DataCount = 0;
3524 pSMB->DataOffset = 0;
3525 pSMB->SetupCount = 1;
3526 pSMB->Reserved3 = 0;
3527 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3528 byte_count = params + 1 /* pad */ ;
3529 pSMB->TotalParameterCount = cpu_to_le16(params);
3530 pSMB->ParameterCount = pSMB->TotalParameterCount;
3531 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3532 pSMB->Reserved4 = 0;
3533 pSMB->hdr.smb_buf_length += byte_count;
3534 pSMB->ByteCount = cpu_to_le16(byte_count);
3535
3536 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3537 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3538 if (rc) {
3539 cFYI(1, ("error %d in QueryInternalInfo", rc));
3540 } else {
3541 /* decode response */
3542 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3543 if (rc || (pSMBr->ByteCount < 2))
3544 /* BB also check enough total bytes returned */
3545 /* If rc should we check for EOPNOSUPP and
3546 disable the srvino flag? or in caller? */
3547 rc = -EIO; /* bad smb */
3548 else {
3549 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3550 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3551 struct file_internal_info * pfinfo;
3552 /* BB Do we need a cast or hash here ? */
3553 if(count < 8) {
3554 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3555 rc = -EIO;
3556 goto GetInodeNumOut;
3557 }
3558 pfinfo = (struct file_internal_info *)
3559 (data_offset + (char *) &pSMBr->hdr.Protocol);
3560 *inode_number = pfinfo->UniqueId;
3561 }
3562 }
3563GetInodeNumOut:
3564 cifs_buf_release(pSMB);
3565 if (rc == -EAGAIN)
3566 goto GetInodeNumberRetry;
3567 return rc;
3568}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
3570int
3571CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3572 const unsigned char *searchName,
3573 unsigned char **targetUNCs,
3574 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003575 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576{
3577/* TRANS2_GET_DFS_REFERRAL */
3578 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3579 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3580 struct dfs_referral_level_3 * referrals = NULL;
3581 int rc = 0;
3582 int bytes_returned;
3583 int name_len;
3584 unsigned int i;
3585 char * temp;
3586 __u16 params, byte_count;
3587 *number_of_UNC_in_array = 0;
3588 *targetUNCs = NULL;
3589
3590 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3591 if (ses == NULL)
3592 return -ENODEV;
3593getDFSRetry:
3594 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3595 (void **) &pSMBr);
3596 if (rc)
3597 return rc;
Steve French1982c342005-08-17 12:38:22 -07003598
3599 /* server pointer checked in called function,
3600 but should never be null here anyway */
3601 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 pSMB->hdr.Tid = ses->ipc_tid;
3603 pSMB->hdr.Uid = ses->Suid;
3604 if (ses->capabilities & CAP_STATUS32) {
3605 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3606 }
3607 if (ses->capabilities & CAP_DFS) {
3608 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3609 }
3610
3611 if (ses->capabilities & CAP_UNICODE) {
3612 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3613 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003614 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003615 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 name_len++; /* trailing null */
3617 name_len *= 2;
3618 } else { /* BB improve the check for buffer overruns BB */
3619 name_len = strnlen(searchName, PATH_MAX);
3620 name_len++; /* trailing null */
3621 strncpy(pSMB->RequestFileName, searchName, name_len);
3622 }
3623
3624 params = 2 /* level */ + name_len /*includes null */ ;
3625 pSMB->TotalDataCount = 0;
3626 pSMB->DataCount = 0;
3627 pSMB->DataOffset = 0;
3628 pSMB->MaxParameterCount = 0;
3629 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3630 pSMB->MaxSetupCount = 0;
3631 pSMB->Reserved = 0;
3632 pSMB->Flags = 0;
3633 pSMB->Timeout = 0;
3634 pSMB->Reserved2 = 0;
3635 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3636 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3637 pSMB->SetupCount = 1;
3638 pSMB->Reserved3 = 0;
3639 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3640 byte_count = params + 3 /* pad */ ;
3641 pSMB->ParameterCount = cpu_to_le16(params);
3642 pSMB->TotalParameterCount = pSMB->ParameterCount;
3643 pSMB->MaxReferralLevel = cpu_to_le16(3);
3644 pSMB->hdr.smb_buf_length += byte_count;
3645 pSMB->ByteCount = cpu_to_le16(byte_count);
3646
3647 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3648 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3649 if (rc) {
3650 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3651 } else { /* decode response */
3652/* BB Add logic to parse referrals here */
3653 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3654
3655 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3656 rc = -EIO; /* bad smb */
3657 else {
3658 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3659 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3660
3661 cFYI(1,
3662 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3663 pSMBr->ByteCount, data_offset));
3664 referrals =
3665 (struct dfs_referral_level_3 *)
3666 (8 /* sizeof start of data block */ +
3667 data_offset +
3668 (char *) &pSMBr->hdr.Protocol);
3669 cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",
3670 le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive)));
3671 /* BB This field is actually two bytes in from start of
3672 data block so we could do safety check that DataBlock
3673 begins at address of pSMBr->NumberOfReferrals */
3674 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3675
3676 /* BB Fix below so can return more than one referral */
3677 if(*number_of_UNC_in_array > 1)
3678 *number_of_UNC_in_array = 1;
3679
3680 /* get the length of the strings describing refs */
3681 name_len = 0;
3682 for(i=0;i<*number_of_UNC_in_array;i++) {
3683 /* make sure that DfsPathOffset not past end */
3684 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3685 if (offset > data_count) {
3686 /* if invalid referral, stop here and do
3687 not try to copy any more */
3688 *number_of_UNC_in_array = i;
3689 break;
3690 }
3691 temp = ((char *)referrals) + offset;
3692
3693 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3694 name_len += UniStrnlen((wchar_t *)temp,data_count);
3695 } else {
3696 name_len += strnlen(temp,data_count);
3697 }
3698 referrals++;
3699 /* BB add check that referral pointer does not fall off end PDU */
3700
3701 }
3702 /* BB add check for name_len bigger than bcc */
3703 *targetUNCs =
3704 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3705 if(*targetUNCs == NULL) {
3706 rc = -ENOMEM;
3707 goto GetDFSRefExit;
3708 }
3709 /* copy the ref strings */
3710 referrals =
3711 (struct dfs_referral_level_3 *)
3712 (8 /* sizeof data hdr */ +
3713 data_offset +
3714 (char *) &pSMBr->hdr.Protocol);
3715
3716 for(i=0;i<*number_of_UNC_in_array;i++) {
3717 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3718 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3719 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003720 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 } else {
3722 strncpy(*targetUNCs,temp,name_len);
3723 }
3724 /* BB update target_uncs pointers */
3725 referrals++;
3726 }
3727 temp = *targetUNCs;
3728 temp[name_len] = 0;
3729 }
3730
3731 }
3732GetDFSRefExit:
3733 if (pSMB)
3734 cifs_buf_release(pSMB);
3735
3736 if (rc == -EAGAIN)
3737 goto getDFSRetry;
3738
3739 return rc;
3740}
3741
Steve French20962432005-09-21 22:05:57 -07003742/* Query File System Info such as free space to old servers such as Win 9x */
3743int
3744SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3745{
3746/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3747 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3748 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3749 FILE_SYSTEM_ALLOC_INFO *response_data;
3750 int rc = 0;
3751 int bytes_returned = 0;
3752 __u16 params, byte_count;
3753
3754 cFYI(1, ("OldQFSInfo"));
3755oldQFSInfoRetry:
3756 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3757 (void **) &pSMBr);
3758 if (rc)
3759 return rc;
3760 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3761 (void **) &pSMBr);
3762 if (rc)
3763 return rc;
3764
3765 params = 2; /* level */
3766 pSMB->TotalDataCount = 0;
3767 pSMB->MaxParameterCount = cpu_to_le16(2);
3768 pSMB->MaxDataCount = cpu_to_le16(1000);
3769 pSMB->MaxSetupCount = 0;
3770 pSMB->Reserved = 0;
3771 pSMB->Flags = 0;
3772 pSMB->Timeout = 0;
3773 pSMB->Reserved2 = 0;
3774 byte_count = params + 1 /* pad */ ;
3775 pSMB->TotalParameterCount = cpu_to_le16(params);
3776 pSMB->ParameterCount = pSMB->TotalParameterCount;
3777 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3778 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3779 pSMB->DataCount = 0;
3780 pSMB->DataOffset = 0;
3781 pSMB->SetupCount = 1;
3782 pSMB->Reserved3 = 0;
3783 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3784 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3785 pSMB->hdr.smb_buf_length += byte_count;
3786 pSMB->ByteCount = cpu_to_le16(byte_count);
3787
3788 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3789 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3790 if (rc) {
3791 cFYI(1, ("Send error in QFSInfo = %d", rc));
3792 } else { /* decode response */
3793 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3794
3795 if (rc || (pSMBr->ByteCount < 18))
3796 rc = -EIO; /* bad smb */
3797 else {
3798 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3799 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3800 pSMBr->ByteCount, data_offset));
3801
3802 response_data =
3803 (FILE_SYSTEM_ALLOC_INFO *)
3804 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3805 FSData->f_bsize =
3806 le16_to_cpu(response_data->BytesPerSector) *
3807 le32_to_cpu(response_data->
3808 SectorsPerAllocationUnit);
3809 FSData->f_blocks =
3810 le32_to_cpu(response_data->TotalAllocationUnits);
3811 FSData->f_bfree = FSData->f_bavail =
3812 le32_to_cpu(response_data->FreeAllocationUnits);
3813 cFYI(1,
3814 ("Blocks: %lld Free: %lld Block size %ld",
3815 (unsigned long long)FSData->f_blocks,
3816 (unsigned long long)FSData->f_bfree,
3817 FSData->f_bsize));
3818 }
3819 }
3820 cifs_buf_release(pSMB);
3821
3822 if (rc == -EAGAIN)
3823 goto oldQFSInfoRetry;
3824
3825 return rc;
3826}
3827
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828int
Steve French737b7582005-04-28 22:41:06 -07003829CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830{
3831/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3832 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3833 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3834 FILE_SYSTEM_INFO *response_data;
3835 int rc = 0;
3836 int bytes_returned = 0;
3837 __u16 params, byte_count;
3838
3839 cFYI(1, ("In QFSInfo"));
3840QFSInfoRetry:
3841 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3842 (void **) &pSMBr);
3843 if (rc)
3844 return rc;
3845
3846 params = 2; /* level */
3847 pSMB->TotalDataCount = 0;
3848 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003849 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 pSMB->MaxSetupCount = 0;
3851 pSMB->Reserved = 0;
3852 pSMB->Flags = 0;
3853 pSMB->Timeout = 0;
3854 pSMB->Reserved2 = 0;
3855 byte_count = params + 1 /* pad */ ;
3856 pSMB->TotalParameterCount = cpu_to_le16(params);
3857 pSMB->ParameterCount = pSMB->TotalParameterCount;
3858 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3859 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3860 pSMB->DataCount = 0;
3861 pSMB->DataOffset = 0;
3862 pSMB->SetupCount = 1;
3863 pSMB->Reserved3 = 0;
3864 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3865 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3866 pSMB->hdr.smb_buf_length += byte_count;
3867 pSMB->ByteCount = cpu_to_le16(byte_count);
3868
3869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3871 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003872 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 } else { /* decode response */
3874 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3875
Steve French20962432005-09-21 22:05:57 -07003876 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 rc = -EIO; /* bad smb */
3878 else {
3879 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880
3881 response_data =
3882 (FILE_SYSTEM_INFO
3883 *) (((char *) &pSMBr->hdr.Protocol) +
3884 data_offset);
3885 FSData->f_bsize =
3886 le32_to_cpu(response_data->BytesPerSector) *
3887 le32_to_cpu(response_data->
3888 SectorsPerAllocationUnit);
3889 FSData->f_blocks =
3890 le64_to_cpu(response_data->TotalAllocationUnits);
3891 FSData->f_bfree = FSData->f_bavail =
3892 le64_to_cpu(response_data->FreeAllocationUnits);
3893 cFYI(1,
3894 ("Blocks: %lld Free: %lld Block size %ld",
3895 (unsigned long long)FSData->f_blocks,
3896 (unsigned long long)FSData->f_bfree,
3897 FSData->f_bsize));
3898 }
3899 }
3900 cifs_buf_release(pSMB);
3901
3902 if (rc == -EAGAIN)
3903 goto QFSInfoRetry;
3904
3905 return rc;
3906}
3907
3908int
Steve French737b7582005-04-28 22:41:06 -07003909CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910{
3911/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3912 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3913 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3914 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3915 int rc = 0;
3916 int bytes_returned = 0;
3917 __u16 params, byte_count;
3918
3919 cFYI(1, ("In QFSAttributeInfo"));
3920QFSAttributeRetry:
3921 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3922 (void **) &pSMBr);
3923 if (rc)
3924 return rc;
3925
3926 params = 2; /* level */
3927 pSMB->TotalDataCount = 0;
3928 pSMB->MaxParameterCount = cpu_to_le16(2);
3929 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3930 pSMB->MaxSetupCount = 0;
3931 pSMB->Reserved = 0;
3932 pSMB->Flags = 0;
3933 pSMB->Timeout = 0;
3934 pSMB->Reserved2 = 0;
3935 byte_count = params + 1 /* pad */ ;
3936 pSMB->TotalParameterCount = cpu_to_le16(params);
3937 pSMB->ParameterCount = pSMB->TotalParameterCount;
3938 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3939 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3940 pSMB->DataCount = 0;
3941 pSMB->DataOffset = 0;
3942 pSMB->SetupCount = 1;
3943 pSMB->Reserved3 = 0;
3944 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3945 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3946 pSMB->hdr.smb_buf_length += byte_count;
3947 pSMB->ByteCount = cpu_to_le16(byte_count);
3948
3949 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3950 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3951 if (rc) {
3952 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3953 } else { /* decode response */
3954 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3955
3956 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3957 rc = -EIO; /* bad smb */
3958 } else {
3959 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3960 response_data =
3961 (FILE_SYSTEM_ATTRIBUTE_INFO
3962 *) (((char *) &pSMBr->hdr.Protocol) +
3963 data_offset);
3964 memcpy(&tcon->fsAttrInfo, response_data,
3965 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3966 }
3967 }
3968 cifs_buf_release(pSMB);
3969
3970 if (rc == -EAGAIN)
3971 goto QFSAttributeRetry;
3972
3973 return rc;
3974}
3975
3976int
Steve French737b7582005-04-28 22:41:06 -07003977CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978{
3979/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3980 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3981 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3982 FILE_SYSTEM_DEVICE_INFO *response_data;
3983 int rc = 0;
3984 int bytes_returned = 0;
3985 __u16 params, byte_count;
3986
3987 cFYI(1, ("In QFSDeviceInfo"));
3988QFSDeviceRetry:
3989 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3990 (void **) &pSMBr);
3991 if (rc)
3992 return rc;
3993
3994 params = 2; /* level */
3995 pSMB->TotalDataCount = 0;
3996 pSMB->MaxParameterCount = cpu_to_le16(2);
3997 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3998 pSMB->MaxSetupCount = 0;
3999 pSMB->Reserved = 0;
4000 pSMB->Flags = 0;
4001 pSMB->Timeout = 0;
4002 pSMB->Reserved2 = 0;
4003 byte_count = params + 1 /* pad */ ;
4004 pSMB->TotalParameterCount = cpu_to_le16(params);
4005 pSMB->ParameterCount = pSMB->TotalParameterCount;
4006 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4007 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4008
4009 pSMB->DataCount = 0;
4010 pSMB->DataOffset = 0;
4011 pSMB->SetupCount = 1;
4012 pSMB->Reserved3 = 0;
4013 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4014 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4015 pSMB->hdr.smb_buf_length += byte_count;
4016 pSMB->ByteCount = cpu_to_le16(byte_count);
4017
4018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4019 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4020 if (rc) {
4021 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4022 } else { /* decode response */
4023 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4024
4025 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4026 rc = -EIO; /* bad smb */
4027 else {
4028 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4029 response_data =
Steve French737b7582005-04-28 22:41:06 -07004030 (FILE_SYSTEM_DEVICE_INFO *)
4031 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 data_offset);
4033 memcpy(&tcon->fsDevInfo, response_data,
4034 sizeof (FILE_SYSTEM_DEVICE_INFO));
4035 }
4036 }
4037 cifs_buf_release(pSMB);
4038
4039 if (rc == -EAGAIN)
4040 goto QFSDeviceRetry;
4041
4042 return rc;
4043}
4044
4045int
Steve French737b7582005-04-28 22:41:06 -07004046CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047{
4048/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4049 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4050 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4051 FILE_SYSTEM_UNIX_INFO *response_data;
4052 int rc = 0;
4053 int bytes_returned = 0;
4054 __u16 params, byte_count;
4055
4056 cFYI(1, ("In QFSUnixInfo"));
4057QFSUnixRetry:
4058 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4059 (void **) &pSMBr);
4060 if (rc)
4061 return rc;
4062
4063 params = 2; /* level */
4064 pSMB->TotalDataCount = 0;
4065 pSMB->DataCount = 0;
4066 pSMB->DataOffset = 0;
4067 pSMB->MaxParameterCount = cpu_to_le16(2);
4068 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4069 pSMB->MaxSetupCount = 0;
4070 pSMB->Reserved = 0;
4071 pSMB->Flags = 0;
4072 pSMB->Timeout = 0;
4073 pSMB->Reserved2 = 0;
4074 byte_count = params + 1 /* pad */ ;
4075 pSMB->ParameterCount = cpu_to_le16(params);
4076 pSMB->TotalParameterCount = pSMB->ParameterCount;
4077 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4078 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4079 pSMB->SetupCount = 1;
4080 pSMB->Reserved3 = 0;
4081 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4082 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4083 pSMB->hdr.smb_buf_length += byte_count;
4084 pSMB->ByteCount = cpu_to_le16(byte_count);
4085
4086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4088 if (rc) {
4089 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4090 } else { /* decode response */
4091 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4092
4093 if (rc || (pSMBr->ByteCount < 13)) {
4094 rc = -EIO; /* bad smb */
4095 } else {
4096 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4097 response_data =
4098 (FILE_SYSTEM_UNIX_INFO
4099 *) (((char *) &pSMBr->hdr.Protocol) +
4100 data_offset);
4101 memcpy(&tcon->fsUnixInfo, response_data,
4102 sizeof (FILE_SYSTEM_UNIX_INFO));
4103 }
4104 }
4105 cifs_buf_release(pSMB);
4106
4107 if (rc == -EAGAIN)
4108 goto QFSUnixRetry;
4109
4110
4111 return rc;
4112}
4113
Jeremy Allisonac670552005-06-22 17:26:35 -07004114int
Steve French45abc6e2005-06-23 13:42:03 -05004115CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004116{
4117/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4118 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4119 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4120 int rc = 0;
4121 int bytes_returned = 0;
4122 __u16 params, param_offset, offset, byte_count;
4123
4124 cFYI(1, ("In SETFSUnixInfo"));
4125SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004126 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004127 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4128 (void **) &pSMBr);
4129 if (rc)
4130 return rc;
4131
4132 params = 4; /* 2 bytes zero followed by info level. */
4133 pSMB->MaxSetupCount = 0;
4134 pSMB->Reserved = 0;
4135 pSMB->Flags = 0;
4136 pSMB->Timeout = 0;
4137 pSMB->Reserved2 = 0;
4138 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4139 offset = param_offset + params;
4140
4141 pSMB->MaxParameterCount = cpu_to_le16(4);
4142 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4143 pSMB->SetupCount = 1;
4144 pSMB->Reserved3 = 0;
4145 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4146 byte_count = 1 /* pad */ + params + 12;
4147
4148 pSMB->DataCount = cpu_to_le16(12);
4149 pSMB->ParameterCount = cpu_to_le16(params);
4150 pSMB->TotalDataCount = pSMB->DataCount;
4151 pSMB->TotalParameterCount = pSMB->ParameterCount;
4152 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4153 pSMB->DataOffset = cpu_to_le16(offset);
4154
4155 /* Params. */
4156 pSMB->FileNum = 0;
4157 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4158
4159 /* Data. */
4160 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4161 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4162 pSMB->ClientUnixCap = cpu_to_le64(cap);
4163
4164 pSMB->hdr.smb_buf_length += byte_count;
4165 pSMB->ByteCount = cpu_to_le16(byte_count);
4166
4167 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4168 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4169 if (rc) {
4170 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4171 } else { /* decode response */
4172 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4173 if (rc) {
4174 rc = -EIO; /* bad smb */
4175 }
4176 }
4177 cifs_buf_release(pSMB);
4178
4179 if (rc == -EAGAIN)
4180 goto SETFSUnixRetry;
4181
4182 return rc;
4183}
4184
4185
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
4187int
4188CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004189 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190{
4191/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4192 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4193 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4194 FILE_SYSTEM_POSIX_INFO *response_data;
4195 int rc = 0;
4196 int bytes_returned = 0;
4197 __u16 params, byte_count;
4198
4199 cFYI(1, ("In QFSPosixInfo"));
4200QFSPosixRetry:
4201 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4202 (void **) &pSMBr);
4203 if (rc)
4204 return rc;
4205
4206 params = 2; /* level */
4207 pSMB->TotalDataCount = 0;
4208 pSMB->DataCount = 0;
4209 pSMB->DataOffset = 0;
4210 pSMB->MaxParameterCount = cpu_to_le16(2);
4211 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4212 pSMB->MaxSetupCount = 0;
4213 pSMB->Reserved = 0;
4214 pSMB->Flags = 0;
4215 pSMB->Timeout = 0;
4216 pSMB->Reserved2 = 0;
4217 byte_count = params + 1 /* pad */ ;
4218 pSMB->ParameterCount = cpu_to_le16(params);
4219 pSMB->TotalParameterCount = pSMB->ParameterCount;
4220 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4221 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4222 pSMB->SetupCount = 1;
4223 pSMB->Reserved3 = 0;
4224 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4225 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4226 pSMB->hdr.smb_buf_length += byte_count;
4227 pSMB->ByteCount = cpu_to_le16(byte_count);
4228
4229 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4230 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4231 if (rc) {
4232 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4233 } else { /* decode response */
4234 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4235
4236 if (rc || (pSMBr->ByteCount < 13)) {
4237 rc = -EIO; /* bad smb */
4238 } else {
4239 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4240 response_data =
4241 (FILE_SYSTEM_POSIX_INFO
4242 *) (((char *) &pSMBr->hdr.Protocol) +
4243 data_offset);
4244 FSData->f_bsize =
4245 le32_to_cpu(response_data->BlockSize);
4246 FSData->f_blocks =
4247 le64_to_cpu(response_data->TotalBlocks);
4248 FSData->f_bfree =
4249 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004250 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 FSData->f_bavail = FSData->f_bfree;
4252 } else {
4253 FSData->f_bavail =
4254 le64_to_cpu(response_data->UserBlocksAvail);
4255 }
Steve French70ca7342005-09-22 16:32:06 -07004256 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257 FSData->f_files =
4258 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004259 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 FSData->f_ffree =
4261 le64_to_cpu(response_data->FreeFileNodes);
4262 }
4263 }
4264 cifs_buf_release(pSMB);
4265
4266 if (rc == -EAGAIN)
4267 goto QFSPosixRetry;
4268
4269 return rc;
4270}
4271
4272
4273/* We can not use write of zero bytes trick to
4274 set file size due to need for large file support. Also note that
4275 this SetPathInfo is preferred to SetFileInfo based method in next
4276 routine which is only needed to work around a sharing violation bug
4277 in Samba which this routine can run into */
4278
4279int
4280CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004281 __u64 size, int SetAllocation,
4282 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283{
4284 struct smb_com_transaction2_spi_req *pSMB = NULL;
4285 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4286 struct file_end_of_file_info *parm_data;
4287 int name_len;
4288 int rc = 0;
4289 int bytes_returned = 0;
4290 __u16 params, byte_count, data_count, param_offset, offset;
4291
4292 cFYI(1, ("In SetEOF"));
4293SetEOFRetry:
4294 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4295 (void **) &pSMBr);
4296 if (rc)
4297 return rc;
4298
4299 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4300 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004301 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004302 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 name_len++; /* trailing null */
4304 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004305 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 name_len = strnlen(fileName, PATH_MAX);
4307 name_len++; /* trailing null */
4308 strncpy(pSMB->FileName, fileName, name_len);
4309 }
4310 params = 6 + name_len;
4311 data_count = sizeof (struct file_end_of_file_info);
4312 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004313 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 pSMB->MaxSetupCount = 0;
4315 pSMB->Reserved = 0;
4316 pSMB->Flags = 0;
4317 pSMB->Timeout = 0;
4318 pSMB->Reserved2 = 0;
4319 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4320 InformationLevel) - 4;
4321 offset = param_offset + params;
4322 if(SetAllocation) {
4323 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4324 pSMB->InformationLevel =
4325 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4326 else
4327 pSMB->InformationLevel =
4328 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4329 } else /* Set File Size */ {
4330 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4331 pSMB->InformationLevel =
4332 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4333 else
4334 pSMB->InformationLevel =
4335 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4336 }
4337
4338 parm_data =
4339 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4340 offset);
4341 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4342 pSMB->DataOffset = cpu_to_le16(offset);
4343 pSMB->SetupCount = 1;
4344 pSMB->Reserved3 = 0;
4345 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4346 byte_count = 3 /* pad */ + params + data_count;
4347 pSMB->DataCount = cpu_to_le16(data_count);
4348 pSMB->TotalDataCount = pSMB->DataCount;
4349 pSMB->ParameterCount = cpu_to_le16(params);
4350 pSMB->TotalParameterCount = pSMB->ParameterCount;
4351 pSMB->Reserved4 = 0;
4352 pSMB->hdr.smb_buf_length += byte_count;
4353 parm_data->FileSize = cpu_to_le64(size);
4354 pSMB->ByteCount = cpu_to_le16(byte_count);
4355 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4356 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4357 if (rc) {
4358 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4359 }
4360
4361 cifs_buf_release(pSMB);
4362
4363 if (rc == -EAGAIN)
4364 goto SetEOFRetry;
4365
4366 return rc;
4367}
4368
4369int
4370CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4371 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4372{
4373 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4374 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4375 char *data_offset;
4376 struct file_end_of_file_info *parm_data;
4377 int rc = 0;
4378 int bytes_returned = 0;
4379 __u16 params, param_offset, offset, byte_count, count;
4380
4381 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4382 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004383 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4384
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 if (rc)
4386 return rc;
4387
Steve Frenchcd634992005-04-28 22:41:10 -07004388 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4389
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4391 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4392
4393 params = 6;
4394 pSMB->MaxSetupCount = 0;
4395 pSMB->Reserved = 0;
4396 pSMB->Flags = 0;
4397 pSMB->Timeout = 0;
4398 pSMB->Reserved2 = 0;
4399 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4400 offset = param_offset + params;
4401
4402 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4403
4404 count = sizeof(struct file_end_of_file_info);
4405 pSMB->MaxParameterCount = cpu_to_le16(2);
4406 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4407 pSMB->SetupCount = 1;
4408 pSMB->Reserved3 = 0;
4409 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4410 byte_count = 3 /* pad */ + params + count;
4411 pSMB->DataCount = cpu_to_le16(count);
4412 pSMB->ParameterCount = cpu_to_le16(params);
4413 pSMB->TotalDataCount = pSMB->DataCount;
4414 pSMB->TotalParameterCount = pSMB->ParameterCount;
4415 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4416 parm_data =
4417 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4418 offset);
4419 pSMB->DataOffset = cpu_to_le16(offset);
4420 parm_data->FileSize = cpu_to_le64(size);
4421 pSMB->Fid = fid;
4422 if(SetAllocation) {
4423 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4424 pSMB->InformationLevel =
4425 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4426 else
4427 pSMB->InformationLevel =
4428 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4429 } else /* Set File Size */ {
4430 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4431 pSMB->InformationLevel =
4432 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4433 else
4434 pSMB->InformationLevel =
4435 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4436 }
4437 pSMB->Reserved4 = 0;
4438 pSMB->hdr.smb_buf_length += byte_count;
4439 pSMB->ByteCount = cpu_to_le16(byte_count);
4440 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4441 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4442 if (rc) {
4443 cFYI(1,
4444 ("Send error in SetFileInfo (SetFileSize) = %d",
4445 rc));
4446 }
4447
4448 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004449 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450
4451 /* Note: On -EAGAIN error only caller can retry on handle based calls
4452 since file handle passed in no longer valid */
4453
4454 return rc;
4455}
4456
4457/* Some legacy servers such as NT4 require that the file times be set on
4458 an open handle, rather than by pathname - this is awkward due to
4459 potential access conflicts on the open, but it is unavoidable for these
4460 old servers since the only other choice is to go from 100 nanosecond DCE
4461 time and resort to the original setpathinfo level which takes the ancient
4462 DOS time format with 2 second granularity */
4463int
4464CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4465 __u16 fid)
4466{
4467 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4468 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4469 char *data_offset;
4470 int rc = 0;
4471 int bytes_returned = 0;
4472 __u16 params, param_offset, offset, byte_count, count;
4473
4474 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004475 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4476
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 if (rc)
4478 return rc;
4479
Steve Frenchcd634992005-04-28 22:41:10 -07004480 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4481
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 /* At this point there is no need to override the current pid
4483 with the pid of the opener, but that could change if we someday
4484 use an existing handle (rather than opening one on the fly) */
4485 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4486 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4487
4488 params = 6;
4489 pSMB->MaxSetupCount = 0;
4490 pSMB->Reserved = 0;
4491 pSMB->Flags = 0;
4492 pSMB->Timeout = 0;
4493 pSMB->Reserved2 = 0;
4494 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4495 offset = param_offset + params;
4496
4497 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4498
4499 count = sizeof (FILE_BASIC_INFO);
4500 pSMB->MaxParameterCount = cpu_to_le16(2);
4501 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4502 pSMB->SetupCount = 1;
4503 pSMB->Reserved3 = 0;
4504 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4505 byte_count = 3 /* pad */ + params + count;
4506 pSMB->DataCount = cpu_to_le16(count);
4507 pSMB->ParameterCount = cpu_to_le16(params);
4508 pSMB->TotalDataCount = pSMB->DataCount;
4509 pSMB->TotalParameterCount = pSMB->ParameterCount;
4510 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4511 pSMB->DataOffset = cpu_to_le16(offset);
4512 pSMB->Fid = fid;
4513 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4514 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4515 else
4516 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4517 pSMB->Reserved4 = 0;
4518 pSMB->hdr.smb_buf_length += byte_count;
4519 pSMB->ByteCount = cpu_to_le16(byte_count);
4520 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4521 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4522 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4523 if (rc) {
4524 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4525 }
4526
Steve Frenchcd634992005-04-28 22:41:10 -07004527 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528
4529 /* Note: On -EAGAIN error only caller can retry on handle based calls
4530 since file handle passed in no longer valid */
4531
4532 return rc;
4533}
4534
4535
4536int
4537CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4538 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004539 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540{
4541 TRANSACTION2_SPI_REQ *pSMB = NULL;
4542 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4543 int name_len;
4544 int rc = 0;
4545 int bytes_returned = 0;
4546 char *data_offset;
4547 __u16 params, param_offset, offset, byte_count, count;
4548
4549 cFYI(1, ("In SetTimes"));
4550
4551SetTimesRetry:
4552 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4553 (void **) &pSMBr);
4554 if (rc)
4555 return rc;
4556
4557 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4558 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004559 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004560 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 name_len++; /* trailing null */
4562 name_len *= 2;
4563 } else { /* BB improve the check for buffer overruns BB */
4564 name_len = strnlen(fileName, PATH_MAX);
4565 name_len++; /* trailing null */
4566 strncpy(pSMB->FileName, fileName, name_len);
4567 }
4568
4569 params = 6 + name_len;
4570 count = sizeof (FILE_BASIC_INFO);
4571 pSMB->MaxParameterCount = cpu_to_le16(2);
4572 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4573 pSMB->MaxSetupCount = 0;
4574 pSMB->Reserved = 0;
4575 pSMB->Flags = 0;
4576 pSMB->Timeout = 0;
4577 pSMB->Reserved2 = 0;
4578 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4579 InformationLevel) - 4;
4580 offset = param_offset + params;
4581 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4582 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4583 pSMB->DataOffset = cpu_to_le16(offset);
4584 pSMB->SetupCount = 1;
4585 pSMB->Reserved3 = 0;
4586 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4587 byte_count = 3 /* pad */ + params + count;
4588
4589 pSMB->DataCount = cpu_to_le16(count);
4590 pSMB->ParameterCount = cpu_to_le16(params);
4591 pSMB->TotalDataCount = pSMB->DataCount;
4592 pSMB->TotalParameterCount = pSMB->ParameterCount;
4593 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4594 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4595 else
4596 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4597 pSMB->Reserved4 = 0;
4598 pSMB->hdr.smb_buf_length += byte_count;
4599 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4600 pSMB->ByteCount = cpu_to_le16(byte_count);
4601 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4602 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4603 if (rc) {
4604 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4605 }
4606
4607 cifs_buf_release(pSMB);
4608
4609 if (rc == -EAGAIN)
4610 goto SetTimesRetry;
4611
4612 return rc;
4613}
4614
4615/* Can not be used to set time stamps yet (due to old DOS time format) */
4616/* Can be used to set attributes */
4617#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4618 handling it anyway and NT4 was what we thought it would be needed for
4619 Do not delete it until we prove whether needed for Win9x though */
4620int
4621CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4622 __u16 dos_attrs, const struct nls_table *nls_codepage)
4623{
4624 SETATTR_REQ *pSMB = NULL;
4625 SETATTR_RSP *pSMBr = NULL;
4626 int rc = 0;
4627 int bytes_returned;
4628 int name_len;
4629
4630 cFYI(1, ("In SetAttrLegacy"));
4631
4632SetAttrLgcyRetry:
4633 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4634 (void **) &pSMBr);
4635 if (rc)
4636 return rc;
4637
4638 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4639 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004640 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 PATH_MAX, nls_codepage);
4642 name_len++; /* trailing null */
4643 name_len *= 2;
4644 } else { /* BB improve the check for buffer overruns BB */
4645 name_len = strnlen(fileName, PATH_MAX);
4646 name_len++; /* trailing null */
4647 strncpy(pSMB->fileName, fileName, name_len);
4648 }
4649 pSMB->attr = cpu_to_le16(dos_attrs);
4650 pSMB->BufferFormat = 0x04;
4651 pSMB->hdr.smb_buf_length += name_len + 1;
4652 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4653 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4654 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4655 if (rc) {
4656 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4657 }
4658
4659 cifs_buf_release(pSMB);
4660
4661 if (rc == -EAGAIN)
4662 goto SetAttrLgcyRetry;
4663
4664 return rc;
4665}
4666#endif /* temporarily unneeded SetAttr legacy function */
4667
4668int
4669CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004670 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4671 dev_t device, const struct nls_table *nls_codepage,
4672 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673{
4674 TRANSACTION2_SPI_REQ *pSMB = NULL;
4675 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4676 int name_len;
4677 int rc = 0;
4678 int bytes_returned = 0;
4679 FILE_UNIX_BASIC_INFO *data_offset;
4680 __u16 params, param_offset, offset, count, byte_count;
4681
4682 cFYI(1, ("In SetUID/GID/Mode"));
4683setPermsRetry:
4684 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4685 (void **) &pSMBr);
4686 if (rc)
4687 return rc;
4688
4689 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4690 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004691 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004692 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 name_len++; /* trailing null */
4694 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004695 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696 name_len = strnlen(fileName, PATH_MAX);
4697 name_len++; /* trailing null */
4698 strncpy(pSMB->FileName, fileName, name_len);
4699 }
4700
4701 params = 6 + name_len;
4702 count = sizeof (FILE_UNIX_BASIC_INFO);
4703 pSMB->MaxParameterCount = cpu_to_le16(2);
4704 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4705 pSMB->MaxSetupCount = 0;
4706 pSMB->Reserved = 0;
4707 pSMB->Flags = 0;
4708 pSMB->Timeout = 0;
4709 pSMB->Reserved2 = 0;
4710 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4711 InformationLevel) - 4;
4712 offset = param_offset + params;
4713 data_offset =
4714 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4715 offset);
4716 memset(data_offset, 0, count);
4717 pSMB->DataOffset = cpu_to_le16(offset);
4718 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4719 pSMB->SetupCount = 1;
4720 pSMB->Reserved3 = 0;
4721 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4722 byte_count = 3 /* pad */ + params + count;
4723 pSMB->ParameterCount = cpu_to_le16(params);
4724 pSMB->DataCount = cpu_to_le16(count);
4725 pSMB->TotalParameterCount = pSMB->ParameterCount;
4726 pSMB->TotalDataCount = pSMB->DataCount;
4727 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4728 pSMB->Reserved4 = 0;
4729 pSMB->hdr.smb_buf_length += byte_count;
4730 data_offset->Uid = cpu_to_le64(uid);
4731 data_offset->Gid = cpu_to_le64(gid);
4732 /* better to leave device as zero when it is */
4733 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4734 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4735 data_offset->Permissions = cpu_to_le64(mode);
4736
4737 if(S_ISREG(mode))
4738 data_offset->Type = cpu_to_le32(UNIX_FILE);
4739 else if(S_ISDIR(mode))
4740 data_offset->Type = cpu_to_le32(UNIX_DIR);
4741 else if(S_ISLNK(mode))
4742 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4743 else if(S_ISCHR(mode))
4744 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4745 else if(S_ISBLK(mode))
4746 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4747 else if(S_ISFIFO(mode))
4748 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4749 else if(S_ISSOCK(mode))
4750 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4751
4752
4753 pSMB->ByteCount = cpu_to_le16(byte_count);
4754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4756 if (rc) {
4757 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4758 }
4759
4760 if (pSMB)
4761 cifs_buf_release(pSMB);
4762 if (rc == -EAGAIN)
4763 goto setPermsRetry;
4764 return rc;
4765}
4766
4767int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004768 const int notify_subdirs, const __u16 netfid,
4769 __u32 filter, struct file * pfile, int multishot,
4770 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771{
4772 int rc = 0;
4773 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004774 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004775 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 int bytes_returned;
4777
4778 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4779 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4780 (void **) &pSMBr);
4781 if (rc)
4782 return rc;
4783
4784 pSMB->TotalParameterCount = 0 ;
4785 pSMB->TotalDataCount = 0;
4786 pSMB->MaxParameterCount = cpu_to_le32(2);
4787 /* BB find exact data count max from sess structure BB */
4788 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004789/* BB VERIFY verify which is correct for above BB */
4790 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4791 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4792
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 pSMB->MaxSetupCount = 4;
4794 pSMB->Reserved = 0;
4795 pSMB->ParameterOffset = 0;
4796 pSMB->DataCount = 0;
4797 pSMB->DataOffset = 0;
4798 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4799 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4800 pSMB->ParameterCount = pSMB->TotalParameterCount;
4801 if(notify_subdirs)
4802 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4803 pSMB->Reserved2 = 0;
4804 pSMB->CompletionFilter = cpu_to_le32(filter);
4805 pSMB->Fid = netfid; /* file handle always le */
4806 pSMB->ByteCount = 0;
4807
4808 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4809 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4810 if (rc) {
4811 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004812 } else {
4813 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004814 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004815 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004816 sizeof(struct dir_notify_req),
4817 GFP_KERNEL);
4818 if(dnotify_req) {
4819 dnotify_req->Pid = pSMB->hdr.Pid;
4820 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4821 dnotify_req->Mid = pSMB->hdr.Mid;
4822 dnotify_req->Tid = pSMB->hdr.Tid;
4823 dnotify_req->Uid = pSMB->hdr.Uid;
4824 dnotify_req->netfid = netfid;
4825 dnotify_req->pfile = pfile;
4826 dnotify_req->filter = filter;
4827 dnotify_req->multishot = multishot;
4828 spin_lock(&GlobalMid_Lock);
4829 list_add_tail(&dnotify_req->lhead,
4830 &GlobalDnotifyReqList);
4831 spin_unlock(&GlobalMid_Lock);
4832 } else
4833 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 }
4835 cifs_buf_release(pSMB);
4836 return rc;
4837}
4838#ifdef CONFIG_CIFS_XATTR
4839ssize_t
4840CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4841 const unsigned char *searchName,
4842 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004843 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844{
4845 /* BB assumes one setup word */
4846 TRANSACTION2_QPI_REQ *pSMB = NULL;
4847 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4848 int rc = 0;
4849 int bytes_returned;
4850 int name_len;
4851 struct fea * temp_fea;
4852 char * temp_ptr;
4853 __u16 params, byte_count;
4854
4855 cFYI(1, ("In Query All EAs path %s", searchName));
4856QAllEAsRetry:
4857 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4858 (void **) &pSMBr);
4859 if (rc)
4860 return rc;
4861
4862 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4863 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004864 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004865 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 name_len++; /* trailing null */
4867 name_len *= 2;
4868 } else { /* BB improve the check for buffer overruns BB */
4869 name_len = strnlen(searchName, PATH_MAX);
4870 name_len++; /* trailing null */
4871 strncpy(pSMB->FileName, searchName, name_len);
4872 }
4873
4874 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4875 pSMB->TotalDataCount = 0;
4876 pSMB->MaxParameterCount = cpu_to_le16(2);
4877 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4878 pSMB->MaxSetupCount = 0;
4879 pSMB->Reserved = 0;
4880 pSMB->Flags = 0;
4881 pSMB->Timeout = 0;
4882 pSMB->Reserved2 = 0;
4883 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4884 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4885 pSMB->DataCount = 0;
4886 pSMB->DataOffset = 0;
4887 pSMB->SetupCount = 1;
4888 pSMB->Reserved3 = 0;
4889 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4890 byte_count = params + 1 /* pad */ ;
4891 pSMB->TotalParameterCount = cpu_to_le16(params);
4892 pSMB->ParameterCount = pSMB->TotalParameterCount;
4893 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4894 pSMB->Reserved4 = 0;
4895 pSMB->hdr.smb_buf_length += byte_count;
4896 pSMB->ByteCount = cpu_to_le16(byte_count);
4897
4898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4899 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4900 if (rc) {
4901 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4902 } else { /* decode response */
4903 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4904
4905 /* BB also check enough total bytes returned */
4906 /* BB we need to improve the validity checking
4907 of these trans2 responses */
4908 if (rc || (pSMBr->ByteCount < 4))
4909 rc = -EIO; /* bad smb */
4910 /* else if (pFindData){
4911 memcpy((char *) pFindData,
4912 (char *) &pSMBr->hdr.Protocol +
4913 data_offset, kl);
4914 }*/ else {
4915 /* check that length of list is not more than bcc */
4916 /* check that each entry does not go beyond length
4917 of list */
4918 /* check that each element of each entry does not
4919 go beyond end of list */
4920 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4921 struct fealist * ea_response_data;
4922 rc = 0;
4923 /* validate_trans2_offsets() */
4924 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4925 ea_response_data = (struct fealist *)
4926 (((char *) &pSMBr->hdr.Protocol) +
4927 data_offset);
4928 name_len = le32_to_cpu(ea_response_data->list_len);
4929 cFYI(1,("ea length %d", name_len));
4930 if(name_len <= 8) {
4931 /* returned EA size zeroed at top of function */
4932 cFYI(1,("empty EA list returned from server"));
4933 } else {
4934 /* account for ea list len */
4935 name_len -= 4;
4936 temp_fea = ea_response_data->list;
4937 temp_ptr = (char *)temp_fea;
4938 while(name_len > 0) {
4939 __u16 value_len;
4940 name_len -= 4;
4941 temp_ptr += 4;
4942 rc += temp_fea->name_len;
4943 /* account for prefix user. and trailing null */
4944 rc = rc + 5 + 1;
4945 if(rc<(int)buf_size) {
4946 memcpy(EAData,"user.",5);
4947 EAData+=5;
4948 memcpy(EAData,temp_ptr,temp_fea->name_len);
4949 EAData+=temp_fea->name_len;
4950 /* null terminate name */
4951 *EAData = 0;
4952 EAData = EAData + 1;
4953 } else if(buf_size == 0) {
4954 /* skip copy - calc size only */
4955 } else {
4956 /* stop before overrun buffer */
4957 rc = -ERANGE;
4958 break;
4959 }
4960 name_len -= temp_fea->name_len;
4961 temp_ptr += temp_fea->name_len;
4962 /* account for trailing null */
4963 name_len--;
4964 temp_ptr++;
4965 value_len = le16_to_cpu(temp_fea->value_len);
4966 name_len -= value_len;
4967 temp_ptr += value_len;
4968 /* BB check that temp_ptr is still within smb BB*/
4969 /* no trailing null to account for in value len */
4970 /* go on to next EA */
4971 temp_fea = (struct fea *)temp_ptr;
4972 }
4973 }
4974 }
4975 }
4976 if (pSMB)
4977 cifs_buf_release(pSMB);
4978 if (rc == -EAGAIN)
4979 goto QAllEAsRetry;
4980
4981 return (ssize_t)rc;
4982}
4983
4984ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4985 const unsigned char * searchName,const unsigned char * ea_name,
4986 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004987 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988{
4989 TRANSACTION2_QPI_REQ *pSMB = NULL;
4990 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4991 int rc = 0;
4992 int bytes_returned;
4993 int name_len;
4994 struct fea * temp_fea;
4995 char * temp_ptr;
4996 __u16 params, byte_count;
4997
4998 cFYI(1, ("In Query EA path %s", searchName));
4999QEARetry:
5000 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5001 (void **) &pSMBr);
5002 if (rc)
5003 return rc;
5004
5005 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5006 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005007 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005008 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009 name_len++; /* trailing null */
5010 name_len *= 2;
5011 } else { /* BB improve the check for buffer overruns BB */
5012 name_len = strnlen(searchName, PATH_MAX);
5013 name_len++; /* trailing null */
5014 strncpy(pSMB->FileName, searchName, name_len);
5015 }
5016
5017 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5018 pSMB->TotalDataCount = 0;
5019 pSMB->MaxParameterCount = cpu_to_le16(2);
5020 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5021 pSMB->MaxSetupCount = 0;
5022 pSMB->Reserved = 0;
5023 pSMB->Flags = 0;
5024 pSMB->Timeout = 0;
5025 pSMB->Reserved2 = 0;
5026 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5027 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5028 pSMB->DataCount = 0;
5029 pSMB->DataOffset = 0;
5030 pSMB->SetupCount = 1;
5031 pSMB->Reserved3 = 0;
5032 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5033 byte_count = params + 1 /* pad */ ;
5034 pSMB->TotalParameterCount = cpu_to_le16(params);
5035 pSMB->ParameterCount = pSMB->TotalParameterCount;
5036 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5037 pSMB->Reserved4 = 0;
5038 pSMB->hdr.smb_buf_length += byte_count;
5039 pSMB->ByteCount = cpu_to_le16(byte_count);
5040
5041 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5042 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5043 if (rc) {
5044 cFYI(1, ("Send error in Query EA = %d", rc));
5045 } else { /* decode response */
5046 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5047
5048 /* BB also check enough total bytes returned */
5049 /* BB we need to improve the validity checking
5050 of these trans2 responses */
5051 if (rc || (pSMBr->ByteCount < 4))
5052 rc = -EIO; /* bad smb */
5053 /* else if (pFindData){
5054 memcpy((char *) pFindData,
5055 (char *) &pSMBr->hdr.Protocol +
5056 data_offset, kl);
5057 }*/ else {
5058 /* check that length of list is not more than bcc */
5059 /* check that each entry does not go beyond length
5060 of list */
5061 /* check that each element of each entry does not
5062 go beyond end of list */
5063 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5064 struct fealist * ea_response_data;
5065 rc = -ENODATA;
5066 /* validate_trans2_offsets() */
5067 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5068 ea_response_data = (struct fealist *)
5069 (((char *) &pSMBr->hdr.Protocol) +
5070 data_offset);
5071 name_len = le32_to_cpu(ea_response_data->list_len);
5072 cFYI(1,("ea length %d", name_len));
5073 if(name_len <= 8) {
5074 /* returned EA size zeroed at top of function */
5075 cFYI(1,("empty EA list returned from server"));
5076 } else {
5077 /* account for ea list len */
5078 name_len -= 4;
5079 temp_fea = ea_response_data->list;
5080 temp_ptr = (char *)temp_fea;
5081 /* loop through checking if we have a matching
5082 name and then return the associated value */
5083 while(name_len > 0) {
5084 __u16 value_len;
5085 name_len -= 4;
5086 temp_ptr += 4;
5087 value_len = le16_to_cpu(temp_fea->value_len);
5088 /* BB validate that value_len falls within SMB,
5089 even though maximum for name_len is 255 */
5090 if(memcmp(temp_fea->name,ea_name,
5091 temp_fea->name_len) == 0) {
5092 /* found a match */
5093 rc = value_len;
5094 /* account for prefix user. and trailing null */
5095 if(rc<=(int)buf_size) {
5096 memcpy(ea_value,
5097 temp_fea->name+temp_fea->name_len+1,
5098 rc);
5099 /* ea values, unlike ea names,
5100 are not null terminated */
5101 } else if(buf_size == 0) {
5102 /* skip copy - calc size only */
5103 } else {
5104 /* stop before overrun buffer */
5105 rc = -ERANGE;
5106 }
5107 break;
5108 }
5109 name_len -= temp_fea->name_len;
5110 temp_ptr += temp_fea->name_len;
5111 /* account for trailing null */
5112 name_len--;
5113 temp_ptr++;
5114 name_len -= value_len;
5115 temp_ptr += value_len;
5116 /* no trailing null to account for in value len */
5117 /* go on to next EA */
5118 temp_fea = (struct fea *)temp_ptr;
5119 }
5120 }
5121 }
5122 }
5123 if (pSMB)
5124 cifs_buf_release(pSMB);
5125 if (rc == -EAGAIN)
5126 goto QEARetry;
5127
5128 return (ssize_t)rc;
5129}
5130
5131int
5132CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5133 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005134 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5135 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136{
5137 struct smb_com_transaction2_spi_req *pSMB = NULL;
5138 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5139 struct fealist *parm_data;
5140 int name_len;
5141 int rc = 0;
5142 int bytes_returned = 0;
5143 __u16 params, param_offset, byte_count, offset, count;
5144
5145 cFYI(1, ("In SetEA"));
5146SetEARetry:
5147 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5148 (void **) &pSMBr);
5149 if (rc)
5150 return rc;
5151
5152 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5153 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005154 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005155 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 name_len++; /* trailing null */
5157 name_len *= 2;
5158 } else { /* BB improve the check for buffer overruns BB */
5159 name_len = strnlen(fileName, PATH_MAX);
5160 name_len++; /* trailing null */
5161 strncpy(pSMB->FileName, fileName, name_len);
5162 }
5163
5164 params = 6 + name_len;
5165
5166 /* done calculating parms using name_len of file name,
5167 now use name_len to calculate length of ea name
5168 we are going to create in the inode xattrs */
5169 if(ea_name == NULL)
5170 name_len = 0;
5171 else
5172 name_len = strnlen(ea_name,255);
5173
5174 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5175 pSMB->MaxParameterCount = cpu_to_le16(2);
5176 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5177 pSMB->MaxSetupCount = 0;
5178 pSMB->Reserved = 0;
5179 pSMB->Flags = 0;
5180 pSMB->Timeout = 0;
5181 pSMB->Reserved2 = 0;
5182 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5183 InformationLevel) - 4;
5184 offset = param_offset + params;
5185 pSMB->InformationLevel =
5186 cpu_to_le16(SMB_SET_FILE_EA);
5187
5188 parm_data =
5189 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5190 offset);
5191 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5192 pSMB->DataOffset = cpu_to_le16(offset);
5193 pSMB->SetupCount = 1;
5194 pSMB->Reserved3 = 0;
5195 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5196 byte_count = 3 /* pad */ + params + count;
5197 pSMB->DataCount = cpu_to_le16(count);
5198 parm_data->list_len = cpu_to_le32(count);
5199 parm_data->list[0].EA_flags = 0;
5200 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005201 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 /* EA names are always ASCII */
5203 if(ea_name)
5204 strncpy(parm_data->list[0].name,ea_name,name_len);
5205 parm_data->list[0].name[name_len] = 0;
5206 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5207 /* caller ensures that ea_value_len is less than 64K but
5208 we need to ensure that it fits within the smb */
5209
5210 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5211 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5212 if(ea_value_len)
5213 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5214
5215 pSMB->TotalDataCount = pSMB->DataCount;
5216 pSMB->ParameterCount = cpu_to_le16(params);
5217 pSMB->TotalParameterCount = pSMB->ParameterCount;
5218 pSMB->Reserved4 = 0;
5219 pSMB->hdr.smb_buf_length += byte_count;
5220 pSMB->ByteCount = cpu_to_le16(byte_count);
5221 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5222 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5223 if (rc) {
5224 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5225 }
5226
5227 cifs_buf_release(pSMB);
5228
5229 if (rc == -EAGAIN)
5230 goto SetEARetry;
5231
5232 return rc;
5233}
5234
5235#endif