blob: de405bfb67d2ec7d7f0c5d0f2a10f77d495797bb [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 French1982c342005-08-17 12:38:22 -0700418 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
Steve French750d1152006-06-27 06:28:30 +0000420 if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000421 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French39798772006-05-31 22:40:51 +0000422
423 count = 0;
424 for(i=0;i<CIFS_NUM_PROT;i++) {
425 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
426 count += strlen(protocols[i].name) + 1;
427 /* null at end of source and target buffers anyway */
428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 pSMB->hdr.smb_buf_length += count;
430 pSMB->ByteCount = cpu_to_le16(count);
431
432 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
433 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French254e55e2006-06-04 05:53:15 +0000434 if (rc != 0)
435 goto neg_err_exit;
436
437 cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
438 /* Check wct = 1 error case */
439 if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
440 /* core returns wct = 1, but we do not ask for core - otherwise
441 small wct just comes when dialect index is -1 indicating we
442 could not negotiate a common dialect */
443 rc = -EOPNOTSUPP;
444 goto neg_err_exit;
445#ifdef CONFIG_CIFS_WEAK_PW_HASH
446 } else if((pSMBr->hdr.WordCount == 13)
447 && (pSMBr->DialectIndex == LANMAN_PROT)) {
448 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
449
Steve French750d1152006-06-27 06:28:30 +0000450 if((secFlags & CIFSSEC_MAY_LANMAN) ||
451 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000452 server->secType = LANMAN;
453 else {
454 cERROR(1, ("mount failed weak security disabled"
455 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000456 rc = -EOPNOTSUPP;
457 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000458 }
459 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
460 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
461 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000462 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000463 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
464 /* even though we do not use raw we might as well set this
465 accurately, in case we ever find a need for it */
466 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
467 server->maxRw = 0xFF00;
468 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
469 } else {
470 server->maxRw = 0;/* we do not need to use raw anyway */
471 server->capabilities = CAP_MPX_MODE;
472 }
473 server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
Steve French39798772006-05-31 22:40:51 +0000474
Steve French254e55e2006-06-04 05:53:15 +0000475 /* BB get server time for time conversions and add
476 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000477
Steve French254e55e2006-06-04 05:53:15 +0000478 if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
479 memcpy(server->cryptKey, rsp->EncryptionKey,
480 CIFS_CRYPTO_KEY_SIZE);
481 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
482 rc = -EIO; /* need cryptkey unless plain text */
483 goto neg_err_exit;
484 }
Steve French39798772006-05-31 22:40:51 +0000485
Steve French254e55e2006-06-04 05:53:15 +0000486 cFYI(1,("LANMAN negotiated"));
487 /* we will not end up setting signing flags - as no signing
488 was in LANMAN and server did not return the flags on */
489 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000490#else /* weak security disabled */
Steve French254e55e2006-06-04 05:53:15 +0000491 } else if(pSMBr->hdr.WordCount == 13) {
492 cERROR(1,("mount failed, cifs module not built "
493 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000494 rc = -EOPNOTSUPP;
495#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000496 goto neg_err_exit;
497 } else if(pSMBr->hdr.WordCount != 17) {
498 /* unknown wct */
499 rc = -EOPNOTSUPP;
500 goto neg_err_exit;
501 }
502 /* else wct == 17 NTLM */
503 server->secMode = pSMBr->SecurityMode;
504 if((server->secMode & SECMODE_USER) == 0)
505 cFYI(1,("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000506
Steve French254e55e2006-06-04 05:53:15 +0000507 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000508#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000509 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000510#endif /* CIFS_WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000511 cERROR(1,("Server requests plain text password"
512 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000513
Steve French750d1152006-06-27 06:28:30 +0000514 if(secFlags & CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000515 server->secType = NTLMv2;
516 else
517 server->secType = NTLM;
518 /* else krb5 ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000519
Steve French254e55e2006-06-04 05:53:15 +0000520 /* one byte, so no need to convert this or EncryptionKeyLen from
521 little endian */
522 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
523 /* probably no need to store and check maxvcs */
524 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000526 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
527 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
528 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
529 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
530 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
531 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
532 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
533 CIFS_CRYPTO_KEY_SIZE);
534 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
535 && (pSMBr->EncryptionKeyLength == 0)) {
536 /* decode security blob */
537 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
538 rc = -EIO; /* no crypt key only if plain text pwd */
539 goto neg_err_exit;
540 }
541
542 /* BB might be helpful to save off the domain of server here */
543
544 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
545 (server->capabilities & CAP_EXTENDED_SECURITY)) {
546 count = pSMBr->ByteCount;
547 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000549 else if (count == 16) {
550 server->secType = RawNTLMSSP;
551 if (server->socketUseCount.counter > 1) {
552 if (memcmp(server->server_GUID,
553 pSMBr->u.extended_response.
554 GUID, 16) != 0) {
555 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000557 pSMBr->u.extended_response.GUID,
558 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 }
Steve French254e55e2006-06-04 05:53:15 +0000560 } else
561 memcpy(server->server_GUID,
562 pSMBr->u.extended_response.GUID, 16);
563 } else {
564 rc = decode_negTokenInit(pSMBr->u.extended_response.
565 SecurityBlob,
566 count - 16,
567 &server->secType);
568 if(rc == 1) {
569 /* BB Need to fill struct for sessetup here */
570 rc = -EOPNOTSUPP;
571 } else {
572 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 }
Steve French254e55e2006-06-04 05:53:15 +0000575 } else
576 server->capabilities &= ~CAP_EXTENDED_SECURITY;
577
Steve French6344a422006-06-12 04:18:35 +0000578#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000579signing_check:
Steve French6344a422006-06-12 04:18:35 +0000580#endif
Steve French254e55e2006-06-04 05:53:15 +0000581 if(sign_CIFS_PDUs == FALSE) {
582 if(server->secMode & SECMODE_SIGN_REQUIRED)
583 cERROR(1,("Server requires "
584 "/proc/fs/cifs/PacketSigningEnabled to be on"));
585 server->secMode &=
586 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
587 } else if(sign_CIFS_PDUs == 1) {
588 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
589 server->secMode &=
590 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
591 } else if(sign_CIFS_PDUs == 2) {
592 if((server->secMode &
593 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
594 cERROR(1,("signing required but server lacks support"));
595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 }
Steve French39798772006-05-31 22:40:51 +0000597neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700598 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000599
600 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 return rc;
602}
603
604int
605CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
606{
607 struct smb_hdr *smb_buffer;
608 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
609 int rc = 0;
610 int length;
611
612 cFYI(1, ("In tree disconnect"));
613 /*
614 * If last user of the connection and
615 * connection alive - disconnect it
616 * If this is the last connection on the server session disconnect it
617 * (and inside session disconnect we should check if tcp socket needs
618 * to be freed and kernel thread woken up).
619 */
620 if (tcon)
621 down(&tcon->tconSem);
622 else
623 return -EIO;
624
625 atomic_dec(&tcon->useCount);
626 if (atomic_read(&tcon->useCount) > 0) {
627 up(&tcon->tconSem);
628 return -EBUSY;
629 }
630
631 /* No need to return error on this operation if tid invalidated and
632 closed on server already e.g. due to tcp session crashing */
633 if(tcon->tidStatus == CifsNeedReconnect) {
634 up(&tcon->tconSem);
635 return 0;
636 }
637
638 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
639 up(&tcon->tconSem);
640 return -EIO;
641 }
Steve French09d1db52005-04-28 22:41:08 -0700642 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
643 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 if (rc) {
645 up(&tcon->tconSem);
646 return rc;
647 } else {
648 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
651 &length, 0);
652 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700653 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655 if (smb_buffer)
656 cifs_small_buf_release(smb_buffer);
657 up(&tcon->tconSem);
658
659 /* No need to return error on this operation if tid invalidated and
660 closed on server already e.g. due to tcp session crashing */
661 if (rc == -EAGAIN)
662 rc = 0;
663
664 return rc;
665}
666
667int
668CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
669{
670 struct smb_hdr *smb_buffer_response;
671 LOGOFF_ANDX_REQ *pSMB;
672 int rc = 0;
673 int length;
674
675 cFYI(1, ("In SMBLogoff for session disconnect"));
676 if (ses)
677 down(&ses->sesSem);
678 else
679 return -EIO;
680
681 atomic_dec(&ses->inUse);
682 if (atomic_read(&ses->inUse) > 0) {
683 up(&ses->sesSem);
684 return -EBUSY;
685 }
686 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
687 if (rc) {
688 up(&ses->sesSem);
689 return rc;
690 }
691
692 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
693
694 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700695 pSMB->hdr.Mid = GetNextMid(ses->server);
696
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 if(ses->server->secMode &
698 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
699 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
700 }
701
702 pSMB->hdr.Uid = ses->Suid;
703
704 pSMB->AndXCommand = 0xFF;
705 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
706 smb_buffer_response, &length, 0);
707 if (ses->server) {
708 atomic_dec(&ses->server->socketUseCount);
709 if (atomic_read(&ses->server->socketUseCount) == 0) {
710 spin_lock(&GlobalMid_Lock);
711 ses->server->tcpStatus = CifsExiting;
712 spin_unlock(&GlobalMid_Lock);
713 rc = -ESHUTDOWN;
714 }
715 }
Steve Frencha59c6582005-08-17 12:12:19 -0700716 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700717 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719 /* if session dead then we do not need to do ulogoff,
720 since server closed smb session, no sense reporting
721 error */
722 if (rc == -EAGAIN)
723 rc = 0;
724 return rc;
725}
726
727int
Steve French737b7582005-04-28 22:41:06 -0700728CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
729 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730{
731 DELETE_FILE_REQ *pSMB = NULL;
732 DELETE_FILE_RSP *pSMBr = NULL;
733 int rc = 0;
734 int bytes_returned;
735 int name_len;
736
737DelFileRetry:
738 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
739 (void **) &pSMBr);
740 if (rc)
741 return rc;
742
743 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
744 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500745 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700746 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 name_len++; /* trailing null */
748 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700749 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 name_len = strnlen(fileName, PATH_MAX);
751 name_len++; /* trailing null */
752 strncpy(pSMB->fileName, fileName, name_len);
753 }
754 pSMB->SearchAttributes =
755 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
756 pSMB->BufferFormat = 0x04;
757 pSMB->hdr.smb_buf_length += name_len + 1;
758 pSMB->ByteCount = cpu_to_le16(name_len + 1);
759 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
760 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700761 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if (rc) {
763 cFYI(1, ("Error in RMFile = %d", rc));
764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
766 cifs_buf_release(pSMB);
767 if (rc == -EAGAIN)
768 goto DelFileRetry;
769
770 return rc;
771}
772
773int
Steve French737b7582005-04-28 22:41:06 -0700774CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
775 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
777 DELETE_DIRECTORY_REQ *pSMB = NULL;
778 DELETE_DIRECTORY_RSP *pSMBr = NULL;
779 int rc = 0;
780 int bytes_returned;
781 int name_len;
782
783 cFYI(1, ("In CIFSSMBRmDir"));
784RmDirRetry:
785 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
786 (void **) &pSMBr);
787 if (rc)
788 return rc;
789
790 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700791 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
792 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 name_len++; /* trailing null */
794 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700795 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 name_len = strnlen(dirName, PATH_MAX);
797 name_len++; /* trailing null */
798 strncpy(pSMB->DirName, dirName, name_len);
799 }
800
801 pSMB->BufferFormat = 0x04;
802 pSMB->hdr.smb_buf_length += name_len + 1;
803 pSMB->ByteCount = cpu_to_le16(name_len + 1);
804 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
805 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700806 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 if (rc) {
808 cFYI(1, ("Error in RMDir = %d", rc));
809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
811 cifs_buf_release(pSMB);
812 if (rc == -EAGAIN)
813 goto RmDirRetry;
814 return rc;
815}
816
817int
818CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700819 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820{
821 int rc = 0;
822 CREATE_DIRECTORY_REQ *pSMB = NULL;
823 CREATE_DIRECTORY_RSP *pSMBr = NULL;
824 int bytes_returned;
825 int name_len;
826
827 cFYI(1, ("In CIFSSMBMkDir"));
828MkDirRetry:
829 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
830 (void **) &pSMBr);
831 if (rc)
832 return rc;
833
834 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500835 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700836 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 name_len++; /* trailing null */
838 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700839 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 name_len = strnlen(name, PATH_MAX);
841 name_len++; /* trailing null */
842 strncpy(pSMB->DirName, name, name_len);
843 }
844
845 pSMB->BufferFormat = 0x04;
846 pSMB->hdr.smb_buf_length += name_len + 1;
847 pSMB->ByteCount = cpu_to_le16(name_len + 1);
848 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
849 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700850 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (rc) {
852 cFYI(1, ("Error in Mkdir = %d", rc));
853 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700854
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 cifs_buf_release(pSMB);
856 if (rc == -EAGAIN)
857 goto MkDirRetry;
858 return rc;
859}
860
Steve Frencha9d02ad2005-08-24 23:06:05 -0700861static __u16 convert_disposition(int disposition)
862{
863 __u16 ofun = 0;
864
865 switch (disposition) {
866 case FILE_SUPERSEDE:
867 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
868 break;
869 case FILE_OPEN:
870 ofun = SMBOPEN_OAPPEND;
871 break;
872 case FILE_CREATE:
873 ofun = SMBOPEN_OCREATE;
874 break;
875 case FILE_OPEN_IF:
876 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
877 break;
878 case FILE_OVERWRITE:
879 ofun = SMBOPEN_OTRUNC;
880 break;
881 case FILE_OVERWRITE_IF:
882 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
883 break;
884 default:
885 cFYI(1,("unknown disposition %d",disposition));
886 ofun = SMBOPEN_OAPPEND; /* regular open */
887 }
888 return ofun;
889}
890
891int
892SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
893 const char *fileName, const int openDisposition,
894 const int access_flags, const int create_options, __u16 * netfid,
895 int *pOplock, FILE_ALL_INFO * pfile_info,
896 const struct nls_table *nls_codepage, int remap)
897{
898 int rc = -EACCES;
899 OPENX_REQ *pSMB = NULL;
900 OPENX_RSP *pSMBr = NULL;
901 int bytes_returned;
902 int name_len;
903 __u16 count;
904
905OldOpenRetry:
906 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
907 (void **) &pSMBr);
908 if (rc)
909 return rc;
910
911 pSMB->AndXCommand = 0xFF; /* none */
912
913 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
914 count = 1; /* account for one byte pad to word boundary */
915 name_len =
916 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
917 fileName, PATH_MAX, nls_codepage, remap);
918 name_len++; /* trailing null */
919 name_len *= 2;
920 } else { /* BB improve check for buffer overruns BB */
921 count = 0; /* no pad */
922 name_len = strnlen(fileName, PATH_MAX);
923 name_len++; /* trailing null */
924 strncpy(pSMB->fileName, fileName, name_len);
925 }
926 if (*pOplock & REQ_OPLOCK)
927 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
928 else if (*pOplock & REQ_BATCHOPLOCK) {
929 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
930 }
931 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
932 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
933 /* 0 = read
934 1 = write
935 2 = rw
936 3 = execute
937 */
938 pSMB->Mode = cpu_to_le16(2);
939 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
940 /* set file as system file if special file such
941 as fifo and server expecting SFU style and
942 no Unix extensions */
943
944 if(create_options & CREATE_OPTION_SPECIAL)
945 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
946 else
Steve French3e87d802005-09-18 20:49:21 -0700947 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700948
949 /* if ((omode & S_IWUGO) == 0)
950 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
951 /* Above line causes problems due to vfs splitting create into two
952 pieces - need to set mode after file created not while it is
953 being created */
954
955 /* BB FIXME BB */
956/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
957 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700958
959 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700960 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700961 count += name_len;
962 pSMB->hdr.smb_buf_length += count;
963
964 pSMB->ByteCount = cpu_to_le16(count);
965 /* long_op set to 1 to allow for oplock break timeouts */
966 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
967 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
968 cifs_stats_inc(&tcon->num_opens);
969 if (rc) {
970 cFYI(1, ("Error in Open = %d", rc));
971 } else {
972 /* BB verify if wct == 15 */
973
974/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
975
976 *netfid = pSMBr->Fid; /* cifs fid stays in le */
977 /* Let caller know file was created so we can set the mode. */
978 /* Do we care about the CreateAction in any other cases? */
979 /* BB FIXME BB */
980/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
981 *pOplock |= CIFS_CREATE_ACTION; */
982 /* BB FIXME END */
983
984 if(pfile_info) {
985 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
986 pfile_info->LastAccessTime = 0; /* BB fixme */
987 pfile_info->LastWriteTime = 0; /* BB fixme */
988 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700989 pfile_info->Attributes =
990 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700991 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700992 pfile_info->AllocationSize =
993 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
994 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700995 pfile_info->NumberOfLinks = cpu_to_le32(1);
996 }
997 }
998
999 cifs_buf_release(pSMB);
1000 if (rc == -EAGAIN)
1001 goto OldOpenRetry;
1002 return rc;
1003}
1004
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005int
1006CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1007 const char *fileName, const int openDisposition,
1008 const int access_flags, const int create_options, __u16 * netfid,
1009 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001010 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011{
1012 int rc = -EACCES;
1013 OPEN_REQ *pSMB = NULL;
1014 OPEN_RSP *pSMBr = NULL;
1015 int bytes_returned;
1016 int name_len;
1017 __u16 count;
1018
1019openRetry:
1020 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1021 (void **) &pSMBr);
1022 if (rc)
1023 return rc;
1024
1025 pSMB->AndXCommand = 0xFF; /* none */
1026
1027 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1028 count = 1; /* account for one byte pad to word boundary */
1029 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001030 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001031 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 name_len++; /* trailing null */
1033 name_len *= 2;
1034 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001035 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 count = 0; /* no pad */
1037 name_len = strnlen(fileName, PATH_MAX);
1038 name_len++; /* trailing null */
1039 pSMB->NameLength = cpu_to_le16(name_len);
1040 strncpy(pSMB->fileName, fileName, name_len);
1041 }
1042 if (*pOplock & REQ_OPLOCK)
1043 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1044 else if (*pOplock & REQ_BATCHOPLOCK) {
1045 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1046 }
1047 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1048 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001049 /* set file as system file if special file such
1050 as fifo and server expecting SFU style and
1051 no Unix extensions */
1052 if(create_options & CREATE_OPTION_SPECIAL)
1053 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1054 else
1055 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 /* XP does not handle ATTR_POSIX_SEMANTICS */
1057 /* but it helps speed up case sensitive checks for other
1058 servers such as Samba */
1059 if (tcon->ses->capabilities & CAP_UNIX)
1060 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1061
1062 /* if ((omode & S_IWUGO) == 0)
1063 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1064 /* Above line causes problems due to vfs splitting create into two
1065 pieces - need to set mode after file created not while it is
1066 being created */
1067 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1068 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001069 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001070 /* BB Expirement with various impersonation levels and verify */
1071 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 pSMB->SecurityFlags =
1073 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1074
1075 count += name_len;
1076 pSMB->hdr.smb_buf_length += count;
1077
1078 pSMB->ByteCount = cpu_to_le16(count);
1079 /* long_op set to 1 to allow for oplock break timeouts */
1080 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1081 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001082 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 if (rc) {
1084 cFYI(1, ("Error in Open = %d", rc));
1085 } else {
Steve French09d1db52005-04-28 22:41:08 -07001086 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1088 /* Let caller know file was created so we can set the mode. */
1089 /* Do we care about the CreateAction in any other cases? */
1090 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1091 *pOplock |= CIFS_CREATE_ACTION;
1092 if(pfile_info) {
1093 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1094 36 /* CreationTime to Attributes */);
1095 /* the file_info buf is endian converted by caller */
1096 pfile_info->AllocationSize = pSMBr->AllocationSize;
1097 pfile_info->EndOfFile = pSMBr->EndOfFile;
1098 pfile_info->NumberOfLinks = cpu_to_le32(1);
1099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001101
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 cifs_buf_release(pSMB);
1103 if (rc == -EAGAIN)
1104 goto openRetry;
1105 return rc;
1106}
1107
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108int
1109CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001110 const int netfid, const unsigned int count,
1111 const __u64 lseek, unsigned int *nbytes, char **buf,
1112 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113{
1114 int rc = -EACCES;
1115 READ_REQ *pSMB = NULL;
1116 READ_RSP *pSMBr = NULL;
1117 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001118 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001119 int resp_buf_type = 0;
1120 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001123 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1124 wct = 12;
1125 else
1126 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
1128 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001129 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 if (rc)
1131 return rc;
1132
1133 /* tcon and ses pointer are checked in smb_init */
1134 if (tcon->ses->server == NULL)
1135 return -ECONNABORTED;
1136
Steve Frenchec637e32005-12-12 20:53:18 -08001137 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 pSMB->Fid = netfid;
1139 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001140 if(wct == 12)
1141 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001142 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1143 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001144
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 pSMB->Remaining = 0;
1146 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1147 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001148 if(wct == 12)
1149 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1150 else {
1151 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001152 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001153 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001154 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001155 }
Steve Frenchec637e32005-12-12 20:53:18 -08001156
1157 iov[0].iov_base = (char *)pSMB;
1158 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1159 rc = SendReceive2(xid, tcon->ses, iov,
1160 1 /* num iovecs */,
1161 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001162 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001163 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 if (rc) {
1165 cERROR(1, ("Send error in read = %d", rc));
1166 } else {
1167 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1168 data_length = data_length << 16;
1169 data_length += le16_to_cpu(pSMBr->DataLength);
1170 *nbytes = data_length;
1171
1172 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001173 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 || (data_length > count)) {
1175 cFYI(1,("bad length %d for count %d",data_length,count));
1176 rc = -EIO;
1177 *nbytes = 0;
1178 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001179 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001181/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1182 cERROR(1,("Faulting on read rc = %d",rc));
1183 rc = -EFAULT;
1184 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001186 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 }
1188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
Steve French4b8f9302006-02-26 16:41:18 +00001190/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001191 if(*buf) {
1192 if(resp_buf_type == CIFS_SMALL_BUFFER)
1193 cifs_small_buf_release(iov[0].iov_base);
1194 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1195 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001196 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1197 /* return buffer to caller to free */
1198 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001199 if(resp_buf_type == CIFS_SMALL_BUFFER)
1200 *pbuf_type = CIFS_SMALL_BUFFER;
1201 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1202 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001203 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001204
1205 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 since file handle passed in no longer valid */
1207 return rc;
1208}
1209
Steve Frenchec637e32005-12-12 20:53:18 -08001210
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211int
1212CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1213 const int netfid, const unsigned int count,
1214 const __u64 offset, unsigned int *nbytes, const char *buf,
1215 const char __user * ubuf, const int long_op)
1216{
1217 int rc = -EACCES;
1218 WRITE_REQ *pSMB = NULL;
1219 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001220 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 __u32 bytes_sent;
1222 __u16 byte_count;
1223
1224 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001225 if(tcon->ses == NULL)
1226 return -ECONNABORTED;
1227
1228 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1229 wct = 14;
1230 else
1231 wct = 12;
1232
1233 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 (void **) &pSMBr);
1235 if (rc)
1236 return rc;
1237 /* tcon and ses pointer are checked in smb_init */
1238 if (tcon->ses->server == NULL)
1239 return -ECONNABORTED;
1240
1241 pSMB->AndXCommand = 0xFF; /* none */
1242 pSMB->Fid = netfid;
1243 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001244 if(wct == 14)
1245 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1246 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1247 return -EIO;
1248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 pSMB->Reserved = 0xFFFFFFFF;
1250 pSMB->WriteMode = 0;
1251 pSMB->Remaining = 0;
1252
1253 /* Can increase buffer size if buffer is big enough in some cases - ie we
1254 can send more if LARGE_WRITE_X capability returned by the server and if
1255 our buffer is big enough or if we convert to iovecs on socket writes
1256 and eliminate the copy to the CIFS buffer */
1257 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1258 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1259 } else {
1260 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1261 & ~0xFF;
1262 }
1263
1264 if (bytes_sent > count)
1265 bytes_sent = count;
1266 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001267 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 if(buf)
1269 memcpy(pSMB->Data,buf,bytes_sent);
1270 else if(ubuf) {
1271 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1272 cifs_buf_release(pSMB);
1273 return -EFAULT;
1274 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001275 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 /* No buffer */
1277 cifs_buf_release(pSMB);
1278 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001279 } /* else setting file size with write of zero bytes */
1280 if(wct == 14)
1281 byte_count = bytes_sent + 1; /* pad */
1282 else /* wct == 12 */ {
1283 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1286 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001287 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001288
1289 if(wct == 14)
1290 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001291 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001292 struct smb_com_writex_req * pSMBW =
1293 (struct smb_com_writex_req *)pSMB;
1294 pSMBW->ByteCount = cpu_to_le16(byte_count);
1295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
1297 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1298 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001299 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (rc) {
1301 cFYI(1, ("Send error in write = %d", rc));
1302 *nbytes = 0;
1303 } else {
1304 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1305 *nbytes = (*nbytes) << 16;
1306 *nbytes += le16_to_cpu(pSMBr->Count);
1307 }
1308
1309 cifs_buf_release(pSMB);
1310
1311 /* Note: On -EAGAIN error only caller can retry on handle based calls
1312 since file handle passed in no longer valid */
1313
1314 return rc;
1315}
1316
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001317int
1318CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001320 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1321 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322{
1323 int rc = -EACCES;
1324 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001325 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001326 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001327 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Steve Frenchff7feac2005-11-15 16:45:16 -08001329 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1330
Steve French8cc64c62005-10-03 13:49:43 -07001331 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1332 wct = 14;
1333 else
1334 wct = 12;
1335 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 if (rc)
1337 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 /* tcon and ses pointer are checked in smb_init */
1339 if (tcon->ses->server == NULL)
1340 return -ECONNABORTED;
1341
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001342 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 pSMB->Fid = netfid;
1344 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001345 if(wct == 14)
1346 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1347 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1348 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 pSMB->Reserved = 0xFFFFFFFF;
1350 pSMB->WriteMode = 0;
1351 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001352
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 pSMB->DataOffset =
1354 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1355
Steve French3e844692005-10-03 13:37:24 -07001356 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1357 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001358 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001359 if(wct == 14)
1360 pSMB->hdr.smb_buf_length += count+1;
1361 else /* wct == 12 */
1362 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1363 if(wct == 14)
1364 pSMB->ByteCount = cpu_to_le16(count + 1);
1365 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1366 struct smb_com_writex_req * pSMBW =
1367 (struct smb_com_writex_req *)pSMB;
1368 pSMBW->ByteCount = cpu_to_le16(count + 5);
1369 }
Steve French3e844692005-10-03 13:37:24 -07001370 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001371 if(wct == 14)
1372 iov[0].iov_len = smb_hdr_len + 4;
1373 else /* wct == 12 pad bigger by four bytes */
1374 iov[0].iov_len = smb_hdr_len + 8;
1375
Steve French3e844692005-10-03 13:37:24 -07001376
Steve Frenchec637e32005-12-12 20:53:18 -08001377 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001378 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001379 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001381 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001383 } else if(resp_buf_type == 0) {
1384 /* presumably this can not happen, but best to be safe */
1385 rc = -EIO;
1386 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001387 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001388 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001389 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1390 *nbytes = (*nbytes) << 16;
1391 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
Steve French4b8f9302006-02-26 16:41:18 +00001394/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001395 if(resp_buf_type == CIFS_SMALL_BUFFER)
1396 cifs_small_buf_release(iov[0].iov_base);
1397 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1398 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
1400 /* Note: On -EAGAIN error only caller can retry on handle based calls
1401 since file handle passed in no longer valid */
1402
1403 return rc;
1404}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001405
1406
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407int
1408CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1409 const __u16 smb_file_id, const __u64 len,
1410 const __u64 offset, const __u32 numUnlock,
1411 const __u32 numLock, const __u8 lockType, const int waitFlag)
1412{
1413 int rc = 0;
1414 LOCK_REQ *pSMB = NULL;
1415 LOCK_RSP *pSMBr = NULL;
1416 int bytes_returned;
1417 int timeout = 0;
1418 __u16 count;
1419
1420 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001421 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1422
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 if (rc)
1424 return rc;
1425
Steve French46810cb2005-04-28 22:41:09 -07001426 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1427
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1429 timeout = -1; /* no response expected */
1430 pSMB->Timeout = 0;
1431 } else if (waitFlag == TRUE) {
1432 timeout = 3; /* blocking operation, no timeout */
1433 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1434 } else {
1435 pSMB->Timeout = 0;
1436 }
1437
1438 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1439 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1440 pSMB->LockType = lockType;
1441 pSMB->AndXCommand = 0xFF; /* none */
1442 pSMB->Fid = smb_file_id; /* netfid stays le */
1443
1444 if((numLock != 0) || (numUnlock != 0)) {
1445 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1446 /* BB where to store pid high? */
1447 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1448 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1449 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1450 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1451 count = sizeof(LOCKING_ANDX_RANGE);
1452 } else {
1453 /* oplock break */
1454 count = 0;
1455 }
1456 pSMB->hdr.smb_buf_length += count;
1457 pSMB->ByteCount = cpu_to_le16(count);
1458
1459 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1460 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001461 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 if (rc) {
1463 cFYI(1, ("Send error in Lock = %d", rc));
1464 }
Steve French46810cb2005-04-28 22:41:09 -07001465 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466
1467 /* Note: On -EAGAIN error only caller can retry on handle based calls
1468 since file handle passed in no longer valid */
1469 return rc;
1470}
1471
1472int
Steve French08547b02006-02-28 22:39:25 +00001473CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1474 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001475 struct file_lock *pLockData, const __u16 lock_type,
1476 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001477{
1478 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1479 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1480 char *data_offset;
1481 struct cifs_posix_lock *parm_data;
1482 int rc = 0;
1483 int bytes_returned = 0;
1484 __u16 params, param_offset, offset, byte_count, count;
1485
1486 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001487
1488 if(pLockData == NULL)
1489 return EINVAL;
1490
Steve French08547b02006-02-28 22:39:25 +00001491 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1492
1493 if (rc)
1494 return rc;
1495
1496 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1497
1498 params = 6;
1499 pSMB->MaxSetupCount = 0;
1500 pSMB->Reserved = 0;
1501 pSMB->Flags = 0;
1502 pSMB->Timeout = 0;
1503 pSMB->Reserved2 = 0;
1504 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1505 offset = param_offset + params;
1506
1507 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1508
1509 count = sizeof(struct cifs_posix_lock);
1510 pSMB->MaxParameterCount = cpu_to_le16(2);
1511 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1512 pSMB->SetupCount = 1;
1513 pSMB->Reserved3 = 0;
1514 if(get_flag)
1515 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1516 else
1517 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1518 byte_count = 3 /* pad */ + params + count;
1519 pSMB->DataCount = cpu_to_le16(count);
1520 pSMB->ParameterCount = cpu_to_le16(params);
1521 pSMB->TotalDataCount = pSMB->DataCount;
1522 pSMB->TotalParameterCount = pSMB->ParameterCount;
1523 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1524 parm_data = (struct cifs_posix_lock *)
1525 (((char *) &pSMB->hdr.Protocol) + offset);
1526
1527 parm_data->lock_type = cpu_to_le16(lock_type);
1528 if(waitFlag)
Steve Frenchcec6815a2006-05-30 18:07:17 +00001529 parm_data->lock_flags = cpu_to_le16(1);
Steve French08547b02006-02-28 22:39:25 +00001530 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001531 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001532 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001533
1534 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001535 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001536 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1537 pSMB->Reserved4 = 0;
1538 pSMB->hdr.smb_buf_length += byte_count;
1539 pSMB->ByteCount = cpu_to_le16(byte_count);
1540 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1541 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1542 if (rc) {
1543 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001544 } else if (get_flag) {
1545 /* lock structure can be returned on get */
1546 __u16 data_offset;
1547 __u16 data_count;
1548 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001549
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001550 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1551 rc = -EIO; /* bad smb */
1552 goto plk_err_exit;
1553 }
1554 if(pLockData == NULL) {
1555 rc = -EINVAL;
1556 goto plk_err_exit;
1557 }
1558 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1559 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1560 if(data_count < sizeof(struct cifs_posix_lock)) {
1561 rc = -EIO;
1562 goto plk_err_exit;
1563 }
1564 parm_data = (struct cifs_posix_lock *)
1565 ((char *)&pSMBr->hdr.Protocol + data_offset);
1566 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1567 pLockData->fl_type = F_UNLCK;
1568 }
1569
1570plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001571 if (pSMB)
1572 cifs_small_buf_release(pSMB);
1573
1574 /* Note: On -EAGAIN error only caller can retry on handle based calls
1575 since file handle passed in no longer valid */
1576
1577 return rc;
1578}
1579
1580
1581int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1583{
1584 int rc = 0;
1585 CLOSE_REQ *pSMB = NULL;
1586 CLOSE_RSP *pSMBr = NULL;
1587 int bytes_returned;
1588 cFYI(1, ("In CIFSSMBClose"));
1589
1590/* do not retry on dead session on close */
1591 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1592 if(rc == -EAGAIN)
1593 return 0;
1594 if (rc)
1595 return rc;
1596
1597 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1598
1599 pSMB->FileID = (__u16) smb_file_id;
1600 pSMB->LastWriteTime = 0;
1601 pSMB->ByteCount = 0;
1602 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001604 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 if (rc) {
1606 if(rc!=-EINTR) {
1607 /* EINTR is expected when user ctl-c to kill app */
1608 cERROR(1, ("Send error in Close = %d", rc));
1609 }
1610 }
1611
1612 cifs_small_buf_release(pSMB);
1613
1614 /* Since session is dead, file will be closed on server already */
1615 if(rc == -EAGAIN)
1616 rc = 0;
1617
1618 return rc;
1619}
1620
1621int
1622CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1623 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001624 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625{
1626 int rc = 0;
1627 RENAME_REQ *pSMB = NULL;
1628 RENAME_RSP *pSMBr = NULL;
1629 int bytes_returned;
1630 int name_len, name_len2;
1631 __u16 count;
1632
1633 cFYI(1, ("In CIFSSMBRename"));
1634renameRetry:
1635 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1636 (void **) &pSMBr);
1637 if (rc)
1638 return rc;
1639
1640 pSMB->BufferFormat = 0x04;
1641 pSMB->SearchAttributes =
1642 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1643 ATTR_DIRECTORY);
1644
1645 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1646 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001647 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001648 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 name_len++; /* trailing null */
1650 name_len *= 2;
1651 pSMB->OldFileName[name_len] = 0x04; /* pad */
1652 /* protocol requires ASCII signature byte on Unicode string */
1653 pSMB->OldFileName[name_len + 1] = 0x00;
1654 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001655 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001656 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1658 name_len2 *= 2; /* convert to bytes */
1659 } else { /* BB improve the check for buffer overruns BB */
1660 name_len = strnlen(fromName, PATH_MAX);
1661 name_len++; /* trailing null */
1662 strncpy(pSMB->OldFileName, fromName, name_len);
1663 name_len2 = strnlen(toName, PATH_MAX);
1664 name_len2++; /* trailing null */
1665 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1666 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1667 name_len2++; /* trailing null */
1668 name_len2++; /* signature byte */
1669 }
1670
1671 count = 1 /* 1st signature byte */ + name_len + name_len2;
1672 pSMB->hdr.smb_buf_length += count;
1673 pSMB->ByteCount = cpu_to_le16(count);
1674
1675 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1676 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001677 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 if (rc) {
1679 cFYI(1, ("Send error in rename = %d", rc));
1680 }
1681
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 cifs_buf_release(pSMB);
1683
1684 if (rc == -EAGAIN)
1685 goto renameRetry;
1686
1687 return rc;
1688}
1689
1690int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001691 int netfid, char * target_name,
1692 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
1694 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1695 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1696 struct set_file_rename * rename_info;
1697 char *data_offset;
1698 char dummy_string[30];
1699 int rc = 0;
1700 int bytes_returned = 0;
1701 int len_of_str;
1702 __u16 params, param_offset, offset, count, byte_count;
1703
1704 cFYI(1, ("Rename to File by handle"));
1705 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1706 (void **) &pSMBr);
1707 if (rc)
1708 return rc;
1709
1710 params = 6;
1711 pSMB->MaxSetupCount = 0;
1712 pSMB->Reserved = 0;
1713 pSMB->Flags = 0;
1714 pSMB->Timeout = 0;
1715 pSMB->Reserved2 = 0;
1716 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1717 offset = param_offset + params;
1718
1719 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1720 rename_info = (struct set_file_rename *) data_offset;
1721 pSMB->MaxParameterCount = cpu_to_le16(2);
1722 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1723 pSMB->SetupCount = 1;
1724 pSMB->Reserved3 = 0;
1725 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1726 byte_count = 3 /* pad */ + params;
1727 pSMB->ParameterCount = cpu_to_le16(params);
1728 pSMB->TotalParameterCount = pSMB->ParameterCount;
1729 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1730 pSMB->DataOffset = cpu_to_le16(offset);
1731 /* construct random name ".cifs_tmp<inodenum><mid>" */
1732 rename_info->overwrite = cpu_to_le32(1);
1733 rename_info->root_fid = 0;
1734 /* unicode only call */
1735 if(target_name == NULL) {
1736 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001737 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001738 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001740 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001741 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 }
1743 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1744 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1745 byte_count += count;
1746 pSMB->DataCount = cpu_to_le16(count);
1747 pSMB->TotalDataCount = pSMB->DataCount;
1748 pSMB->Fid = netfid;
1749 pSMB->InformationLevel =
1750 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1751 pSMB->Reserved4 = 0;
1752 pSMB->hdr.smb_buf_length += byte_count;
1753 pSMB->ByteCount = cpu_to_le16(byte_count);
1754 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001756 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if (rc) {
1758 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1759 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001760
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 cifs_buf_release(pSMB);
1762
1763 /* Note: On -EAGAIN error only caller can retry on handle based calls
1764 since file handle passed in no longer valid */
1765
1766 return rc;
1767}
1768
1769int
1770CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1771 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001772 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773{
1774 int rc = 0;
1775 COPY_REQ *pSMB = NULL;
1776 COPY_RSP *pSMBr = NULL;
1777 int bytes_returned;
1778 int name_len, name_len2;
1779 __u16 count;
1780
1781 cFYI(1, ("In CIFSSMBCopy"));
1782copyRetry:
1783 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1784 (void **) &pSMBr);
1785 if (rc)
1786 return rc;
1787
1788 pSMB->BufferFormat = 0x04;
1789 pSMB->Tid2 = target_tid;
1790
1791 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1792
1793 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001794 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001795 fromName, PATH_MAX, nls_codepage,
1796 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 name_len++; /* trailing null */
1798 name_len *= 2;
1799 pSMB->OldFileName[name_len] = 0x04; /* pad */
1800 /* protocol requires ASCII signature byte on Unicode string */
1801 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001802 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001803 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1805 name_len2 *= 2; /* convert to bytes */
1806 } else { /* BB improve the check for buffer overruns BB */
1807 name_len = strnlen(fromName, PATH_MAX);
1808 name_len++; /* trailing null */
1809 strncpy(pSMB->OldFileName, fromName, name_len);
1810 name_len2 = strnlen(toName, PATH_MAX);
1811 name_len2++; /* trailing null */
1812 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1813 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1814 name_len2++; /* trailing null */
1815 name_len2++; /* signature byte */
1816 }
1817
1818 count = 1 /* 1st signature byte */ + name_len + name_len2;
1819 pSMB->hdr.smb_buf_length += count;
1820 pSMB->ByteCount = cpu_to_le16(count);
1821
1822 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1823 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1824 if (rc) {
1825 cFYI(1, ("Send error in copy = %d with %d files copied",
1826 rc, le16_to_cpu(pSMBr->CopyCount)));
1827 }
1828 if (pSMB)
1829 cifs_buf_release(pSMB);
1830
1831 if (rc == -EAGAIN)
1832 goto copyRetry;
1833
1834 return rc;
1835}
1836
1837int
1838CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1839 const char *fromName, const char *toName,
1840 const struct nls_table *nls_codepage)
1841{
1842 TRANSACTION2_SPI_REQ *pSMB = NULL;
1843 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1844 char *data_offset;
1845 int name_len;
1846 int name_len_target;
1847 int rc = 0;
1848 int bytes_returned = 0;
1849 __u16 params, param_offset, offset, byte_count;
1850
1851 cFYI(1, ("In Symlink Unix style"));
1852createSymLinkRetry:
1853 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1854 (void **) &pSMBr);
1855 if (rc)
1856 return rc;
1857
1858 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1859 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001860 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 /* find define for this maxpathcomponent */
1862 , nls_codepage);
1863 name_len++; /* trailing null */
1864 name_len *= 2;
1865
1866 } else { /* BB improve the check for buffer overruns BB */
1867 name_len = strnlen(fromName, PATH_MAX);
1868 name_len++; /* trailing null */
1869 strncpy(pSMB->FileName, fromName, name_len);
1870 }
1871 params = 6 + name_len;
1872 pSMB->MaxSetupCount = 0;
1873 pSMB->Reserved = 0;
1874 pSMB->Flags = 0;
1875 pSMB->Timeout = 0;
1876 pSMB->Reserved2 = 0;
1877 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1878 InformationLevel) - 4;
1879 offset = param_offset + params;
1880
1881 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1882 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1883 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001884 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 /* find define for this maxpathcomponent */
1886 , nls_codepage);
1887 name_len_target++; /* trailing null */
1888 name_len_target *= 2;
1889 } else { /* BB improve the check for buffer overruns BB */
1890 name_len_target = strnlen(toName, PATH_MAX);
1891 name_len_target++; /* trailing null */
1892 strncpy(data_offset, toName, name_len_target);
1893 }
1894
1895 pSMB->MaxParameterCount = cpu_to_le16(2);
1896 /* BB find exact max on data count below from sess */
1897 pSMB->MaxDataCount = cpu_to_le16(1000);
1898 pSMB->SetupCount = 1;
1899 pSMB->Reserved3 = 0;
1900 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1901 byte_count = 3 /* pad */ + params + name_len_target;
1902 pSMB->DataCount = cpu_to_le16(name_len_target);
1903 pSMB->ParameterCount = cpu_to_le16(params);
1904 pSMB->TotalDataCount = pSMB->DataCount;
1905 pSMB->TotalParameterCount = pSMB->ParameterCount;
1906 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1907 pSMB->DataOffset = cpu_to_le16(offset);
1908 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1909 pSMB->Reserved4 = 0;
1910 pSMB->hdr.smb_buf_length += byte_count;
1911 pSMB->ByteCount = cpu_to_le16(byte_count);
1912 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1913 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001914 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 if (rc) {
1916 cFYI(1,
1917 ("Send error in SetPathInfo (create symlink) = %d",
1918 rc));
1919 }
1920
1921 if (pSMB)
1922 cifs_buf_release(pSMB);
1923
1924 if (rc == -EAGAIN)
1925 goto createSymLinkRetry;
1926
1927 return rc;
1928}
1929
1930int
1931CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1932 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001933 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934{
1935 TRANSACTION2_SPI_REQ *pSMB = NULL;
1936 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1937 char *data_offset;
1938 int name_len;
1939 int name_len_target;
1940 int rc = 0;
1941 int bytes_returned = 0;
1942 __u16 params, param_offset, offset, byte_count;
1943
1944 cFYI(1, ("In Create Hard link Unix style"));
1945createHardLinkRetry:
1946 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1947 (void **) &pSMBr);
1948 if (rc)
1949 return rc;
1950
1951 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001952 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001953 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 name_len++; /* trailing null */
1955 name_len *= 2;
1956
1957 } else { /* BB improve the check for buffer overruns BB */
1958 name_len = strnlen(toName, PATH_MAX);
1959 name_len++; /* trailing null */
1960 strncpy(pSMB->FileName, toName, name_len);
1961 }
1962 params = 6 + name_len;
1963 pSMB->MaxSetupCount = 0;
1964 pSMB->Reserved = 0;
1965 pSMB->Flags = 0;
1966 pSMB->Timeout = 0;
1967 pSMB->Reserved2 = 0;
1968 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1969 InformationLevel) - 4;
1970 offset = param_offset + params;
1971
1972 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1973 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1974 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001975 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001976 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 name_len_target++; /* trailing null */
1978 name_len_target *= 2;
1979 } else { /* BB improve the check for buffer overruns BB */
1980 name_len_target = strnlen(fromName, PATH_MAX);
1981 name_len_target++; /* trailing null */
1982 strncpy(data_offset, fromName, name_len_target);
1983 }
1984
1985 pSMB->MaxParameterCount = cpu_to_le16(2);
1986 /* BB find exact max on data count below from sess*/
1987 pSMB->MaxDataCount = cpu_to_le16(1000);
1988 pSMB->SetupCount = 1;
1989 pSMB->Reserved3 = 0;
1990 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1991 byte_count = 3 /* pad */ + params + name_len_target;
1992 pSMB->ParameterCount = cpu_to_le16(params);
1993 pSMB->TotalParameterCount = pSMB->ParameterCount;
1994 pSMB->DataCount = cpu_to_le16(name_len_target);
1995 pSMB->TotalDataCount = pSMB->DataCount;
1996 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1997 pSMB->DataOffset = cpu_to_le16(offset);
1998 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1999 pSMB->Reserved4 = 0;
2000 pSMB->hdr.smb_buf_length += byte_count;
2001 pSMB->ByteCount = cpu_to_le16(byte_count);
2002 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002004 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 if (rc) {
2006 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2007 }
2008
2009 cifs_buf_release(pSMB);
2010 if (rc == -EAGAIN)
2011 goto createHardLinkRetry;
2012
2013 return rc;
2014}
2015
2016int
2017CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2018 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002019 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020{
2021 int rc = 0;
2022 NT_RENAME_REQ *pSMB = NULL;
2023 RENAME_RSP *pSMBr = NULL;
2024 int bytes_returned;
2025 int name_len, name_len2;
2026 __u16 count;
2027
2028 cFYI(1, ("In CIFSCreateHardLink"));
2029winCreateHardLinkRetry:
2030
2031 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2032 (void **) &pSMBr);
2033 if (rc)
2034 return rc;
2035
2036 pSMB->SearchAttributes =
2037 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2038 ATTR_DIRECTORY);
2039 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2040 pSMB->ClusterCount = 0;
2041
2042 pSMB->BufferFormat = 0x04;
2043
2044 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2045 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002046 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002047 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 name_len++; /* trailing null */
2049 name_len *= 2;
2050 pSMB->OldFileName[name_len] = 0; /* pad */
2051 pSMB->OldFileName[name_len + 1] = 0x04;
2052 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002053 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002054 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2056 name_len2 *= 2; /* convert to bytes */
2057 } else { /* BB improve the check for buffer overruns BB */
2058 name_len = strnlen(fromName, PATH_MAX);
2059 name_len++; /* trailing null */
2060 strncpy(pSMB->OldFileName, fromName, name_len);
2061 name_len2 = strnlen(toName, PATH_MAX);
2062 name_len2++; /* trailing null */
2063 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2064 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2065 name_len2++; /* trailing null */
2066 name_len2++; /* signature byte */
2067 }
2068
2069 count = 1 /* string type byte */ + name_len + name_len2;
2070 pSMB->hdr.smb_buf_length += count;
2071 pSMB->ByteCount = cpu_to_le16(count);
2072
2073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002075 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 if (rc) {
2077 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2078 }
2079 cifs_buf_release(pSMB);
2080 if (rc == -EAGAIN)
2081 goto winCreateHardLinkRetry;
2082
2083 return rc;
2084}
2085
2086int
2087CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2088 const unsigned char *searchName,
2089 char *symlinkinfo, const int buflen,
2090 const struct nls_table *nls_codepage)
2091{
2092/* SMB_QUERY_FILE_UNIX_LINK */
2093 TRANSACTION2_QPI_REQ *pSMB = NULL;
2094 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2095 int rc = 0;
2096 int bytes_returned;
2097 int name_len;
2098 __u16 params, byte_count;
2099
2100 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2101
2102querySymLinkRetry:
2103 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2104 (void **) &pSMBr);
2105 if (rc)
2106 return rc;
2107
2108 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2109 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002110 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 /* find define for this maxpathcomponent */
2112 , nls_codepage);
2113 name_len++; /* trailing null */
2114 name_len *= 2;
2115 } else { /* BB improve the check for buffer overruns BB */
2116 name_len = strnlen(searchName, PATH_MAX);
2117 name_len++; /* trailing null */
2118 strncpy(pSMB->FileName, searchName, name_len);
2119 }
2120
2121 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2122 pSMB->TotalDataCount = 0;
2123 pSMB->MaxParameterCount = cpu_to_le16(2);
2124 /* BB find exact max data count below from sess structure BB */
2125 pSMB->MaxDataCount = cpu_to_le16(4000);
2126 pSMB->MaxSetupCount = 0;
2127 pSMB->Reserved = 0;
2128 pSMB->Flags = 0;
2129 pSMB->Timeout = 0;
2130 pSMB->Reserved2 = 0;
2131 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2132 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2133 pSMB->DataCount = 0;
2134 pSMB->DataOffset = 0;
2135 pSMB->SetupCount = 1;
2136 pSMB->Reserved3 = 0;
2137 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2138 byte_count = params + 1 /* pad */ ;
2139 pSMB->TotalParameterCount = cpu_to_le16(params);
2140 pSMB->ParameterCount = pSMB->TotalParameterCount;
2141 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2142 pSMB->Reserved4 = 0;
2143 pSMB->hdr.smb_buf_length += byte_count;
2144 pSMB->ByteCount = cpu_to_le16(byte_count);
2145
2146 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2147 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2148 if (rc) {
2149 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2150 } else {
2151 /* decode response */
2152
2153 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2154 if (rc || (pSMBr->ByteCount < 2))
2155 /* BB also check enough total bytes returned */
2156 rc = -EIO; /* bad smb */
2157 else {
2158 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2159 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2160
2161 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2162 name_len = UniStrnlen((wchar_t *) ((char *)
2163 &pSMBr->hdr.Protocol +data_offset),
2164 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002165 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002167 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 data_offset),
2169 name_len, nls_codepage);
2170 } else {
2171 strncpy(symlinkinfo,
2172 (char *) &pSMBr->hdr.Protocol +
2173 data_offset,
2174 min_t(const int, buflen, count));
2175 }
2176 symlinkinfo[buflen] = 0;
2177 /* just in case so calling code does not go off the end of buffer */
2178 }
2179 }
2180 cifs_buf_release(pSMB);
2181 if (rc == -EAGAIN)
2182 goto querySymLinkRetry;
2183 return rc;
2184}
2185
Steve French0a4b92c2006-01-12 15:44:21 -08002186/* Initialize NT TRANSACT SMB into small smb request buffer.
2187 This assumes that all NT TRANSACTS that we init here have
2188 total parm and data under about 400 bytes (to fit in small cifs
2189 buffer size), which is the case so far, it easily fits. NB:
2190 Setup words themselves and ByteCount
2191 MaxSetupCount (size of returned setup area) and
2192 MaxParameterCount (returned parms size) must be set by caller */
2193static int
2194smb_init_ntransact(const __u16 sub_command, const int setup_count,
2195 const int parm_len, struct cifsTconInfo *tcon,
2196 void ** ret_buf)
2197{
2198 int rc;
2199 __u32 temp_offset;
2200 struct smb_com_ntransact_req * pSMB;
2201
2202 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2203 (void **)&pSMB);
2204 if (rc)
2205 return rc;
2206 *ret_buf = (void *)pSMB;
2207 pSMB->Reserved = 0;
2208 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2209 pSMB->TotalDataCount = 0;
2210 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2211 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2212 pSMB->ParameterCount = pSMB->TotalParameterCount;
2213 pSMB->DataCount = pSMB->TotalDataCount;
2214 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2215 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2216 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2217 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2218 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2219 pSMB->SubCommand = cpu_to_le16(sub_command);
2220 return 0;
2221}
2222
2223static int
2224validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2225 int * pdatalen, int * pparmlen)
2226{
2227 char * end_of_smb;
2228 __u32 data_count, data_offset, parm_count, parm_offset;
2229 struct smb_com_ntransact_rsp * pSMBr;
2230
2231 if(buf == NULL)
2232 return -EINVAL;
2233
2234 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2235
2236 /* ByteCount was converted from little endian in SendReceive */
2237 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2238 (char *)&pSMBr->ByteCount;
2239
2240
2241 data_offset = le32_to_cpu(pSMBr->DataOffset);
2242 data_count = le32_to_cpu(pSMBr->DataCount);
2243 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2244 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2245
2246 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2247 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2248
2249 /* should we also check that parm and data areas do not overlap? */
2250 if(*ppparm > end_of_smb) {
2251 cFYI(1,("parms start after end of smb"));
2252 return -EINVAL;
2253 } else if(parm_count + *ppparm > end_of_smb) {
2254 cFYI(1,("parm end after end of smb"));
2255 return -EINVAL;
2256 } else if(*ppdata > end_of_smb) {
2257 cFYI(1,("data starts after end of smb"));
2258 return -EINVAL;
2259 } else if(data_count + *ppdata > end_of_smb) {
2260 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2261 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2262 return -EINVAL;
2263 } else if(parm_count + data_count > pSMBr->ByteCount) {
2264 cFYI(1,("parm count and data count larger than SMB"));
2265 return -EINVAL;
2266 }
2267 return 0;
2268}
2269
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270int
2271CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2272 const unsigned char *searchName,
2273 char *symlinkinfo, const int buflen,__u16 fid,
2274 const struct nls_table *nls_codepage)
2275{
2276 int rc = 0;
2277 int bytes_returned;
2278 int name_len;
2279 struct smb_com_transaction_ioctl_req * pSMB;
2280 struct smb_com_transaction_ioctl_rsp * pSMBr;
2281
2282 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2283 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2284 (void **) &pSMBr);
2285 if (rc)
2286 return rc;
2287
2288 pSMB->TotalParameterCount = 0 ;
2289 pSMB->TotalDataCount = 0;
2290 pSMB->MaxParameterCount = cpu_to_le32(2);
2291 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002292 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2293 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 pSMB->MaxSetupCount = 4;
2295 pSMB->Reserved = 0;
2296 pSMB->ParameterOffset = 0;
2297 pSMB->DataCount = 0;
2298 pSMB->DataOffset = 0;
2299 pSMB->SetupCount = 4;
2300 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2301 pSMB->ParameterCount = pSMB->TotalParameterCount;
2302 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2303 pSMB->IsFsctl = 1; /* FSCTL */
2304 pSMB->IsRootFlag = 0;
2305 pSMB->Fid = fid; /* file handle always le */
2306 pSMB->ByteCount = 0;
2307
2308 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2309 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2310 if (rc) {
2311 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2312 } else { /* decode response */
2313 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2314 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2315 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2316 /* BB also check enough total bytes returned */
2317 rc = -EIO; /* bad smb */
2318 else {
2319 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002320 char * end_of_smb = 2 /* sizeof byte count */ +
2321 pSMBr->ByteCount +
2322 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
2324 struct reparse_data * reparse_buf = (struct reparse_data *)
2325 ((char *)&pSMBr->hdr.Protocol + data_offset);
2326 if((char*)reparse_buf >= end_of_smb) {
2327 rc = -EIO;
2328 goto qreparse_out;
2329 }
2330 if((reparse_buf->LinkNamesBuf +
2331 reparse_buf->TargetNameOffset +
2332 reparse_buf->TargetNameLen) >
2333 end_of_smb) {
2334 cFYI(1,("reparse buf extended beyond SMB"));
2335 rc = -EIO;
2336 goto qreparse_out;
2337 }
2338
2339 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2340 name_len = UniStrnlen((wchar_t *)
2341 (reparse_buf->LinkNamesBuf +
2342 reparse_buf->TargetNameOffset),
2343 min(buflen/2, reparse_buf->TargetNameLen / 2));
2344 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002345 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 reparse_buf->TargetNameOffset),
2347 name_len, nls_codepage);
2348 } else { /* ASCII names */
2349 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2350 reparse_buf->TargetNameOffset,
2351 min_t(const int, buflen, reparse_buf->TargetNameLen));
2352 }
2353 } else {
2354 rc = -EIO;
2355 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2356 }
2357 symlinkinfo[buflen] = 0; /* just in case so the caller
2358 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002359 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 }
2361 }
2362qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002363 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
2365 /* Note: On -EAGAIN error only caller can retry on handle based calls
2366 since file handle passed in no longer valid */
2367
2368 return rc;
2369}
2370
2371#ifdef CONFIG_CIFS_POSIX
2372
2373/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2374static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2375{
2376 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002377 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2378 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2379 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2381
2382 return;
2383}
2384
2385/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002386static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2387 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388{
2389 int size = 0;
2390 int i;
2391 __u16 count;
2392 struct cifs_posix_ace * pACE;
2393 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2394 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2395
2396 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2397 return -EOPNOTSUPP;
2398
2399 if(acl_type & ACL_TYPE_ACCESS) {
2400 count = le16_to_cpu(cifs_acl->access_entry_count);
2401 pACE = &cifs_acl->ace_array[0];
2402 size = sizeof(struct cifs_posix_acl);
2403 size += sizeof(struct cifs_posix_ace) * count;
2404 /* check if we would go beyond end of SMB */
2405 if(size_of_data_area < size) {
2406 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2407 return -EINVAL;
2408 }
2409 } else if(acl_type & ACL_TYPE_DEFAULT) {
2410 count = le16_to_cpu(cifs_acl->access_entry_count);
2411 size = sizeof(struct cifs_posix_acl);
2412 size += sizeof(struct cifs_posix_ace) * count;
2413/* skip past access ACEs to get to default ACEs */
2414 pACE = &cifs_acl->ace_array[count];
2415 count = le16_to_cpu(cifs_acl->default_entry_count);
2416 size += sizeof(struct cifs_posix_ace) * count;
2417 /* check if we would go beyond end of SMB */
2418 if(size_of_data_area < size)
2419 return -EINVAL;
2420 } else {
2421 /* illegal type */
2422 return -EINVAL;
2423 }
2424
2425 size = posix_acl_xattr_size(count);
2426 if((buflen == 0) || (local_acl == NULL)) {
2427 /* used to query ACL EA size */
2428 } else if(size > buflen) {
2429 return -ERANGE;
2430 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002431 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 for(i = 0;i < count ;i++) {
2433 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2434 pACE ++;
2435 }
2436 }
2437 return size;
2438}
2439
2440static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2441 const posix_acl_xattr_entry * local_ace)
2442{
2443 __u16 rc = 0; /* 0 = ACL converted ok */
2444
Steve Frenchff7feac2005-11-15 16:45:16 -08002445 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2446 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002448 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 /* Probably no need to le convert -1 on any arch but can not hurt */
2450 cifs_ace->cifs_uid = cpu_to_le64(-1);
2451 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002452 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2454 return rc;
2455}
2456
2457/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2458static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2459 const int acl_type)
2460{
2461 __u16 rc = 0;
2462 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2463 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2464 int count;
2465 int i;
2466
2467 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2468 return 0;
2469
2470 count = posix_acl_xattr_count((size_t)buflen);
2471 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002472 count, buflen, le32_to_cpu(local_acl->a_version)));
2473 if(le32_to_cpu(local_acl->a_version) != 2) {
2474 cFYI(1,("unknown POSIX ACL version %d",
2475 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 return 0;
2477 }
2478 cifs_acl->version = cpu_to_le16(1);
2479 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002480 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002482 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 else {
2484 cFYI(1,("unknown ACL type %d",acl_type));
2485 return 0;
2486 }
2487 for(i=0;i<count;i++) {
2488 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2489 &local_acl->a_entries[i]);
2490 if(rc != 0) {
2491 /* ACE not converted */
2492 break;
2493 }
2494 }
2495 if(rc == 0) {
2496 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2497 rc += sizeof(struct cifs_posix_acl);
2498 /* BB add check to make sure ACL does not overflow SMB */
2499 }
2500 return rc;
2501}
2502
2503int
2504CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2505 const unsigned char *searchName,
2506 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002507 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508{
2509/* SMB_QUERY_POSIX_ACL */
2510 TRANSACTION2_QPI_REQ *pSMB = NULL;
2511 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2512 int rc = 0;
2513 int bytes_returned;
2514 int name_len;
2515 __u16 params, byte_count;
2516
2517 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2518
2519queryAclRetry:
2520 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2521 (void **) &pSMBr);
2522 if (rc)
2523 return rc;
2524
2525 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2526 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002527 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002528 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 name_len++; /* trailing null */
2530 name_len *= 2;
2531 pSMB->FileName[name_len] = 0;
2532 pSMB->FileName[name_len+1] = 0;
2533 } else { /* BB improve the check for buffer overruns BB */
2534 name_len = strnlen(searchName, PATH_MAX);
2535 name_len++; /* trailing null */
2536 strncpy(pSMB->FileName, searchName, name_len);
2537 }
2538
2539 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2540 pSMB->TotalDataCount = 0;
2541 pSMB->MaxParameterCount = cpu_to_le16(2);
2542 /* BB find exact max data count below from sess structure BB */
2543 pSMB->MaxDataCount = cpu_to_le16(4000);
2544 pSMB->MaxSetupCount = 0;
2545 pSMB->Reserved = 0;
2546 pSMB->Flags = 0;
2547 pSMB->Timeout = 0;
2548 pSMB->Reserved2 = 0;
2549 pSMB->ParameterOffset = cpu_to_le16(
2550 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2551 pSMB->DataCount = 0;
2552 pSMB->DataOffset = 0;
2553 pSMB->SetupCount = 1;
2554 pSMB->Reserved3 = 0;
2555 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2556 byte_count = params + 1 /* pad */ ;
2557 pSMB->TotalParameterCount = cpu_to_le16(params);
2558 pSMB->ParameterCount = pSMB->TotalParameterCount;
2559 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2560 pSMB->Reserved4 = 0;
2561 pSMB->hdr.smb_buf_length += byte_count;
2562 pSMB->ByteCount = cpu_to_le16(byte_count);
2563
2564 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2565 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002566 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 if (rc) {
2568 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2569 } else {
2570 /* decode response */
2571
2572 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2573 if (rc || (pSMBr->ByteCount < 2))
2574 /* BB also check enough total bytes returned */
2575 rc = -EIO; /* bad smb */
2576 else {
2577 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2578 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2579 rc = cifs_copy_posix_acl(acl_inf,
2580 (char *)&pSMBr->hdr.Protocol+data_offset,
2581 buflen,acl_type,count);
2582 }
2583 }
2584 cifs_buf_release(pSMB);
2585 if (rc == -EAGAIN)
2586 goto queryAclRetry;
2587 return rc;
2588}
2589
2590int
2591CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2592 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002593 const char *local_acl, const int buflen,
2594 const int acl_type,
2595 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596{
2597 struct smb_com_transaction2_spi_req *pSMB = NULL;
2598 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2599 char *parm_data;
2600 int name_len;
2601 int rc = 0;
2602 int bytes_returned = 0;
2603 __u16 params, byte_count, data_count, param_offset, offset;
2604
2605 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2606setAclRetry:
2607 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2608 (void **) &pSMBr);
2609 if (rc)
2610 return rc;
2611 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2612 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002613 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002614 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 name_len++; /* trailing null */
2616 name_len *= 2;
2617 } else { /* BB improve the check for buffer overruns BB */
2618 name_len = strnlen(fileName, PATH_MAX);
2619 name_len++; /* trailing null */
2620 strncpy(pSMB->FileName, fileName, name_len);
2621 }
2622 params = 6 + name_len;
2623 pSMB->MaxParameterCount = cpu_to_le16(2);
2624 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2625 pSMB->MaxSetupCount = 0;
2626 pSMB->Reserved = 0;
2627 pSMB->Flags = 0;
2628 pSMB->Timeout = 0;
2629 pSMB->Reserved2 = 0;
2630 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2631 InformationLevel) - 4;
2632 offset = param_offset + params;
2633 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2634 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2635
2636 /* convert to on the wire format for POSIX ACL */
2637 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2638
2639 if(data_count == 0) {
2640 rc = -EOPNOTSUPP;
2641 goto setACLerrorExit;
2642 }
2643 pSMB->DataOffset = cpu_to_le16(offset);
2644 pSMB->SetupCount = 1;
2645 pSMB->Reserved3 = 0;
2646 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2647 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2648 byte_count = 3 /* pad */ + params + data_count;
2649 pSMB->DataCount = cpu_to_le16(data_count);
2650 pSMB->TotalDataCount = pSMB->DataCount;
2651 pSMB->ParameterCount = cpu_to_le16(params);
2652 pSMB->TotalParameterCount = pSMB->ParameterCount;
2653 pSMB->Reserved4 = 0;
2654 pSMB->hdr.smb_buf_length += byte_count;
2655 pSMB->ByteCount = cpu_to_le16(byte_count);
2656 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2657 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2658 if (rc) {
2659 cFYI(1, ("Set POSIX ACL returned %d", rc));
2660 }
2661
2662setACLerrorExit:
2663 cifs_buf_release(pSMB);
2664 if (rc == -EAGAIN)
2665 goto setAclRetry;
2666 return rc;
2667}
2668
Steve Frenchf654bac2005-04-28 22:41:04 -07002669/* BB fix tabs in this function FIXME BB */
2670int
2671CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2672 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2673{
2674 int rc = 0;
2675 struct smb_t2_qfi_req *pSMB = NULL;
2676 struct smb_t2_qfi_rsp *pSMBr = NULL;
2677 int bytes_returned;
2678 __u16 params, byte_count;
2679
2680 cFYI(1,("In GetExtAttr"));
2681 if(tcon == NULL)
2682 return -ENODEV;
2683
2684GetExtAttrRetry:
2685 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2686 (void **) &pSMBr);
2687 if (rc)
2688 return rc;
2689
Steve Frenchc67593a2005-04-28 22:41:04 -07002690 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002691 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002692 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002693 /* BB find exact max data count below from sess structure BB */
2694 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2695 pSMB->t2.MaxSetupCount = 0;
2696 pSMB->t2.Reserved = 0;
2697 pSMB->t2.Flags = 0;
2698 pSMB->t2.Timeout = 0;
2699 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002700 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2701 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002702 pSMB->t2.DataCount = 0;
2703 pSMB->t2.DataOffset = 0;
2704 pSMB->t2.SetupCount = 1;
2705 pSMB->t2.Reserved3 = 0;
2706 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002707 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002708 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2709 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2710 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002711 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002712 pSMB->Fid = netfid;
2713 pSMB->hdr.smb_buf_length += byte_count;
2714 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2715
2716 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2717 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2718 if (rc) {
2719 cFYI(1, ("error %d in GetExtAttr", rc));
2720 } else {
2721 /* decode response */
2722 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2723 if (rc || (pSMBr->ByteCount < 2))
2724 /* BB also check enough total bytes returned */
2725 /* If rc should we check for EOPNOSUPP and
2726 disable the srvino flag? or in caller? */
2727 rc = -EIO; /* bad smb */
2728 else {
2729 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2730 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2731 struct file_chattr_info * pfinfo;
2732 /* BB Do we need a cast or hash here ? */
2733 if(count != 16) {
2734 cFYI(1, ("Illegal size ret in GetExtAttr"));
2735 rc = -EIO;
2736 goto GetExtAttrOut;
2737 }
2738 pfinfo = (struct file_chattr_info *)
2739 (data_offset + (char *) &pSMBr->hdr.Protocol);
2740 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2741 *pMask = le64_to_cpu(pfinfo->mask);
2742 }
2743 }
2744GetExtAttrOut:
2745 cifs_buf_release(pSMB);
2746 if (rc == -EAGAIN)
2747 goto GetExtAttrRetry;
2748 return rc;
2749}
2750
2751
2752#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
Steve Frencheeac8042006-01-13 21:34:58 -08002754
2755/* security id for everyone */
2756const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2757/* group users */
2758const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2759
Steve French0a4b92c2006-01-12 15:44:21 -08002760/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002761static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002762{
Steve French0a4b92c2006-01-12 15:44:21 -08002763 return 0;
2764}
2765
2766/* Get Security Descriptor (by handle) from remote server for a file or dir */
2767int
2768CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2769 /* BB fix up return info */ char *acl_inf, const int buflen,
2770 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2771{
2772 int rc = 0;
2773 int buf_type = 0;
2774 QUERY_SEC_DESC_REQ * pSMB;
2775 struct kvec iov[1];
2776
2777 cFYI(1, ("GetCifsACL"));
2778
2779 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2780 8 /* parm len */, tcon, (void **) &pSMB);
2781 if (rc)
2782 return rc;
2783
2784 pSMB->MaxParameterCount = cpu_to_le32(4);
2785 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2786 pSMB->MaxSetupCount = 0;
2787 pSMB->Fid = fid; /* file handle always le */
2788 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2789 CIFS_ACL_DACL);
2790 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2791 pSMB->hdr.smb_buf_length += 11;
2792 iov[0].iov_base = (char *)pSMB;
2793 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2794
2795 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2796 cifs_stats_inc(&tcon->num_acl_get);
2797 if (rc) {
2798 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2799 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002800 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002801 __le32 * parm;
2802 int parm_len;
2803 int data_len;
2804 int acl_len;
2805 struct smb_com_ntransact_rsp * pSMBr;
2806
2807/* validate_nttransact */
2808 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2809 (char **)&psec_desc,
2810 &parm_len, &data_len);
2811
2812 if(rc)
2813 goto qsec_out;
2814 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2815
2816 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2817
2818 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2819 rc = -EIO; /* bad smb */
2820 goto qsec_out;
2821 }
2822
2823/* BB check that data area is minimum length and as big as acl_len */
2824
2825 acl_len = le32_to_cpu(*(__le32 *)parm);
2826 /* BB check if(acl_len > bufsize) */
2827
2828 parse_sec_desc(psec_desc, acl_len);
2829 }
2830qsec_out:
2831 if(buf_type == CIFS_SMALL_BUFFER)
2832 cifs_small_buf_release(iov[0].iov_base);
2833 else if(buf_type == CIFS_LARGE_BUFFER)
2834 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002835/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002836 return rc;
2837}
2838
2839
Steve French6b8edfe2005-08-23 20:26:03 -07002840/* Legacy Query Path Information call for lookup to old servers such
2841 as Win9x/WinME */
2842int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2843 const unsigned char *searchName,
2844 FILE_ALL_INFO * pFinfo,
2845 const struct nls_table *nls_codepage, int remap)
2846{
2847 QUERY_INFORMATION_REQ * pSMB;
2848 QUERY_INFORMATION_RSP * pSMBr;
2849 int rc = 0;
2850 int bytes_returned;
2851 int name_len;
2852
2853 cFYI(1, ("In SMBQPath path %s", searchName));
2854QInfRetry:
2855 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2856 (void **) &pSMBr);
2857 if (rc)
2858 return rc;
2859
2860 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2861 name_len =
2862 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2863 PATH_MAX, nls_codepage, remap);
2864 name_len++; /* trailing null */
2865 name_len *= 2;
2866 } else {
2867 name_len = strnlen(searchName, PATH_MAX);
2868 name_len++; /* trailing null */
2869 strncpy(pSMB->FileName, searchName, name_len);
2870 }
2871 pSMB->BufferFormat = 0x04;
2872 name_len++; /* account for buffer type byte */
2873 pSMB->hdr.smb_buf_length += (__u16) name_len;
2874 pSMB->ByteCount = cpu_to_le16(name_len);
2875
2876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2878 if (rc) {
2879 cFYI(1, ("Send error in QueryInfo = %d", rc));
2880 } else if (pFinfo) { /* decode response */
2881 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002882 pFinfo->AllocationSize =
2883 cpu_to_le64(le32_to_cpu(pSMBr->size));
2884 pFinfo->EndOfFile = pFinfo->AllocationSize;
2885 pFinfo->Attributes =
2886 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002887 } else
2888 rc = -EIO; /* bad buffer passed in */
2889
2890 cifs_buf_release(pSMB);
2891
2892 if (rc == -EAGAIN)
2893 goto QInfRetry;
2894
2895 return rc;
2896}
2897
2898
2899
2900
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901int
2902CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2903 const unsigned char *searchName,
2904 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002905 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906{
2907/* level 263 SMB_QUERY_FILE_ALL_INFO */
2908 TRANSACTION2_QPI_REQ *pSMB = NULL;
2909 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2910 int rc = 0;
2911 int bytes_returned;
2912 int name_len;
2913 __u16 params, byte_count;
2914
2915/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2916QPathInfoRetry:
2917 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2918 (void **) &pSMBr);
2919 if (rc)
2920 return rc;
2921
2922 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2923 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002924 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002925 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 name_len++; /* trailing null */
2927 name_len *= 2;
2928 } else { /* BB improve the check for buffer overruns BB */
2929 name_len = strnlen(searchName, PATH_MAX);
2930 name_len++; /* trailing null */
2931 strncpy(pSMB->FileName, searchName, name_len);
2932 }
2933
2934 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2935 pSMB->TotalDataCount = 0;
2936 pSMB->MaxParameterCount = cpu_to_le16(2);
2937 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2938 pSMB->MaxSetupCount = 0;
2939 pSMB->Reserved = 0;
2940 pSMB->Flags = 0;
2941 pSMB->Timeout = 0;
2942 pSMB->Reserved2 = 0;
2943 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2944 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2945 pSMB->DataCount = 0;
2946 pSMB->DataOffset = 0;
2947 pSMB->SetupCount = 1;
2948 pSMB->Reserved3 = 0;
2949 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2950 byte_count = params + 1 /* pad */ ;
2951 pSMB->TotalParameterCount = cpu_to_le16(params);
2952 pSMB->ParameterCount = pSMB->TotalParameterCount;
2953 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2954 pSMB->Reserved4 = 0;
2955 pSMB->hdr.smb_buf_length += byte_count;
2956 pSMB->ByteCount = cpu_to_le16(byte_count);
2957
2958 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2959 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2960 if (rc) {
2961 cFYI(1, ("Send error in QPathInfo = %d", rc));
2962 } else { /* decode response */
2963 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2964
2965 if (rc || (pSMBr->ByteCount < 40))
2966 rc = -EIO; /* bad smb */
2967 else if (pFindData){
2968 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2969 memcpy((char *) pFindData,
2970 (char *) &pSMBr->hdr.Protocol +
2971 data_offset, sizeof (FILE_ALL_INFO));
2972 } else
2973 rc = -ENOMEM;
2974 }
2975 cifs_buf_release(pSMB);
2976 if (rc == -EAGAIN)
2977 goto QPathInfoRetry;
2978
2979 return rc;
2980}
2981
2982int
2983CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2984 const unsigned char *searchName,
2985 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002986 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987{
2988/* SMB_QUERY_FILE_UNIX_BASIC */
2989 TRANSACTION2_QPI_REQ *pSMB = NULL;
2990 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2991 int rc = 0;
2992 int bytes_returned = 0;
2993 int name_len;
2994 __u16 params, byte_count;
2995
2996 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2997UnixQPathInfoRetry:
2998 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2999 (void **) &pSMBr);
3000 if (rc)
3001 return rc;
3002
3003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3004 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003005 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003006 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 name_len++; /* trailing null */
3008 name_len *= 2;
3009 } else { /* BB improve the check for buffer overruns BB */
3010 name_len = strnlen(searchName, PATH_MAX);
3011 name_len++; /* trailing null */
3012 strncpy(pSMB->FileName, searchName, name_len);
3013 }
3014
3015 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3016 pSMB->TotalDataCount = 0;
3017 pSMB->MaxParameterCount = cpu_to_le16(2);
3018 /* BB find exact max SMB PDU from sess structure BB */
3019 pSMB->MaxDataCount = cpu_to_le16(4000);
3020 pSMB->MaxSetupCount = 0;
3021 pSMB->Reserved = 0;
3022 pSMB->Flags = 0;
3023 pSMB->Timeout = 0;
3024 pSMB->Reserved2 = 0;
3025 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3026 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3027 pSMB->DataCount = 0;
3028 pSMB->DataOffset = 0;
3029 pSMB->SetupCount = 1;
3030 pSMB->Reserved3 = 0;
3031 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3032 byte_count = params + 1 /* pad */ ;
3033 pSMB->TotalParameterCount = cpu_to_le16(params);
3034 pSMB->ParameterCount = pSMB->TotalParameterCount;
3035 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3036 pSMB->Reserved4 = 0;
3037 pSMB->hdr.smb_buf_length += byte_count;
3038 pSMB->ByteCount = cpu_to_le16(byte_count);
3039
3040 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3041 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3042 if (rc) {
3043 cFYI(1, ("Send error in QPathInfo = %d", rc));
3044 } else { /* decode response */
3045 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3046
3047 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3048 rc = -EIO; /* bad smb */
3049 } else {
3050 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3051 memcpy((char *) pFindData,
3052 (char *) &pSMBr->hdr.Protocol +
3053 data_offset,
3054 sizeof (FILE_UNIX_BASIC_INFO));
3055 }
3056 }
3057 cifs_buf_release(pSMB);
3058 if (rc == -EAGAIN)
3059 goto UnixQPathInfoRetry;
3060
3061 return rc;
3062}
3063
3064#if 0 /* function unused at present */
3065int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3066 const char *searchName, FILE_ALL_INFO * findData,
3067 const struct nls_table *nls_codepage)
3068{
3069/* level 257 SMB_ */
3070 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3071 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3072 int rc = 0;
3073 int bytes_returned;
3074 int name_len;
3075 __u16 params, byte_count;
3076
3077 cFYI(1, ("In FindUnique"));
3078findUniqueRetry:
3079 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3080 (void **) &pSMBr);
3081 if (rc)
3082 return rc;
3083
3084 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3085 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003086 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 /* find define for this maxpathcomponent */
3088 , nls_codepage);
3089 name_len++; /* trailing null */
3090 name_len *= 2;
3091 } else { /* BB improve the check for buffer overruns BB */
3092 name_len = strnlen(searchName, PATH_MAX);
3093 name_len++; /* trailing null */
3094 strncpy(pSMB->FileName, searchName, name_len);
3095 }
3096
3097 params = 12 + name_len /* includes null */ ;
3098 pSMB->TotalDataCount = 0; /* no EAs */
3099 pSMB->MaxParameterCount = cpu_to_le16(2);
3100 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3101 pSMB->MaxSetupCount = 0;
3102 pSMB->Reserved = 0;
3103 pSMB->Flags = 0;
3104 pSMB->Timeout = 0;
3105 pSMB->Reserved2 = 0;
3106 pSMB->ParameterOffset = cpu_to_le16(
3107 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3108 pSMB->DataCount = 0;
3109 pSMB->DataOffset = 0;
3110 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3111 pSMB->Reserved3 = 0;
3112 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3113 byte_count = params + 1 /* pad */ ;
3114 pSMB->TotalParameterCount = cpu_to_le16(params);
3115 pSMB->ParameterCount = pSMB->TotalParameterCount;
3116 pSMB->SearchAttributes =
3117 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3118 ATTR_DIRECTORY);
3119 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3120 pSMB->SearchFlags = cpu_to_le16(1);
3121 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3122 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3123 pSMB->hdr.smb_buf_length += byte_count;
3124 pSMB->ByteCount = cpu_to_le16(byte_count);
3125
3126 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3127 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3128
3129 if (rc) {
3130 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3131 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003132 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 /* BB fill in */
3134 }
3135
3136 cifs_buf_release(pSMB);
3137 if (rc == -EAGAIN)
3138 goto findUniqueRetry;
3139
3140 return rc;
3141}
3142#endif /* end unused (temporarily) function */
3143
3144/* xid, tcon, searchName and codepage are input parms, rest are returned */
3145int
3146CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3147 const char *searchName,
3148 const struct nls_table *nls_codepage,
3149 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003150 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151{
3152/* level 257 SMB_ */
3153 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3154 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3155 T2_FFIRST_RSP_PARMS * parms;
3156 int rc = 0;
3157 int bytes_returned = 0;
3158 int name_len;
3159 __u16 params, byte_count;
3160
Steve French737b7582005-04-28 22:41:06 -07003161 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
3163findFirstRetry:
3164 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3165 (void **) &pSMBr);
3166 if (rc)
3167 return rc;
3168
3169 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3170 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003171 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003172 PATH_MAX, nls_codepage, remap);
3173 /* We can not add the asterik earlier in case
3174 it got remapped to 0xF03A as if it were part of the
3175 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003177 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003178 pSMB->FileName[name_len+1] = 0;
3179 pSMB->FileName[name_len+2] = '*';
3180 pSMB->FileName[name_len+3] = 0;
3181 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3183 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003184 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 } else { /* BB add check for overrun of SMB buf BB */
3186 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187/* BB fix here and in unicode clause above ie
3188 if(name_len > buffersize-header)
3189 free buffer exit; BB */
3190 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003191 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003192 pSMB->FileName[name_len+1] = '*';
3193 pSMB->FileName[name_len+2] = 0;
3194 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 }
3196
3197 params = 12 + name_len /* includes null */ ;
3198 pSMB->TotalDataCount = 0; /* no EAs */
3199 pSMB->MaxParameterCount = cpu_to_le16(10);
3200 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3201 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3202 pSMB->MaxSetupCount = 0;
3203 pSMB->Reserved = 0;
3204 pSMB->Flags = 0;
3205 pSMB->Timeout = 0;
3206 pSMB->Reserved2 = 0;
3207 byte_count = params + 1 /* pad */ ;
3208 pSMB->TotalParameterCount = cpu_to_le16(params);
3209 pSMB->ParameterCount = pSMB->TotalParameterCount;
3210 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003211 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3212 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 pSMB->DataCount = 0;
3214 pSMB->DataOffset = 0;
3215 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3216 pSMB->Reserved3 = 0;
3217 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3218 pSMB->SearchAttributes =
3219 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3220 ATTR_DIRECTORY);
3221 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3222 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3223 CIFS_SEARCH_RETURN_RESUME);
3224 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3225
3226 /* BB what should we set StorageType to? Does it matter? BB */
3227 pSMB->SearchStorageType = 0;
3228 pSMB->hdr.smb_buf_length += byte_count;
3229 pSMB->ByteCount = cpu_to_le16(byte_count);
3230
3231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3232 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003233 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234
Steve French88274812006-03-09 22:21:45 +00003235 if (rc) {/* BB add logic to retry regular search if Unix search
3236 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 /* BB Add code to handle unsupported level rc */
3238 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003239
Steve French88274812006-03-09 22:21:45 +00003240 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
3242 /* BB eventually could optimize out free and realloc of buf */
3243 /* for this case */
3244 if (rc == -EAGAIN)
3245 goto findFirstRetry;
3246 } else { /* decode response */
3247 /* BB remember to free buffer if error BB */
3248 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3249 if(rc == 0) {
3250 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3251 psrch_inf->unicode = TRUE;
3252 else
3253 psrch_inf->unicode = FALSE;
3254
3255 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003256 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 psrch_inf->srch_entries_start =
3258 (char *) &pSMBr->hdr.Protocol +
3259 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3261 le16_to_cpu(pSMBr->t2.ParameterOffset));
3262
3263 if(parms->EndofSearch)
3264 psrch_inf->endOfSearch = TRUE;
3265 else
3266 psrch_inf->endOfSearch = FALSE;
3267
3268 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003269 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 *pnetfid = parms->SearchHandle;
3272 } else {
3273 cifs_buf_release(pSMB);
3274 }
3275 }
3276
3277 return rc;
3278}
3279
3280int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3281 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3282{
3283 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3284 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3285 T2_FNEXT_RSP_PARMS * parms;
3286 char *response_data;
3287 int rc = 0;
3288 int bytes_returned, name_len;
3289 __u16 params, byte_count;
3290
3291 cFYI(1, ("In FindNext"));
3292
3293 if(psrch_inf->endOfSearch == TRUE)
3294 return -ENOENT;
3295
3296 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3297 (void **) &pSMBr);
3298 if (rc)
3299 return rc;
3300
3301 params = 14; /* includes 2 bytes of null string, converted to LE below */
3302 byte_count = 0;
3303 pSMB->TotalDataCount = 0; /* no EAs */
3304 pSMB->MaxParameterCount = cpu_to_le16(8);
3305 pSMB->MaxDataCount =
3306 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3307 pSMB->MaxSetupCount = 0;
3308 pSMB->Reserved = 0;
3309 pSMB->Flags = 0;
3310 pSMB->Timeout = 0;
3311 pSMB->Reserved2 = 0;
3312 pSMB->ParameterOffset = cpu_to_le16(
3313 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3314 pSMB->DataCount = 0;
3315 pSMB->DataOffset = 0;
3316 pSMB->SetupCount = 1;
3317 pSMB->Reserved3 = 0;
3318 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3319 pSMB->SearchHandle = searchHandle; /* always kept as le */
3320 pSMB->SearchCount =
3321 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3322 /* test for Unix extensions */
3323/* if (tcon->ses->capabilities & CAP_UNIX) {
3324 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3325 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3326 } else {
3327 pSMB->InformationLevel =
3328 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3329 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3330 } */
3331 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3332 pSMB->ResumeKey = psrch_inf->resume_key;
3333 pSMB->SearchFlags =
3334 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3335
3336 name_len = psrch_inf->resume_name_len;
3337 params += name_len;
3338 if(name_len < PATH_MAX) {
3339 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3340 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003341 /* 14 byte parm len above enough for 2 byte null terminator */
3342 pSMB->ResumeFileName[name_len] = 0;
3343 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 } else {
3345 rc = -EINVAL;
3346 goto FNext2_err_exit;
3347 }
3348 byte_count = params + 1 /* pad */ ;
3349 pSMB->TotalParameterCount = cpu_to_le16(params);
3350 pSMB->ParameterCount = pSMB->TotalParameterCount;
3351 pSMB->hdr.smb_buf_length += byte_count;
3352 pSMB->ByteCount = cpu_to_le16(byte_count);
3353
3354 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3355 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003356 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 if (rc) {
3358 if (rc == -EBADF) {
3359 psrch_inf->endOfSearch = TRUE;
3360 rc = 0; /* search probably was closed at end of search above */
3361 } else
3362 cFYI(1, ("FindNext returned = %d", rc));
3363 } else { /* decode response */
3364 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3365
3366 if(rc == 0) {
3367 /* BB fixme add lock for file (srch_info) struct here */
3368 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3369 psrch_inf->unicode = TRUE;
3370 else
3371 psrch_inf->unicode = FALSE;
3372 response_data = (char *) &pSMBr->hdr.Protocol +
3373 le16_to_cpu(pSMBr->t2.ParameterOffset);
3374 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3375 response_data = (char *)&pSMBr->hdr.Protocol +
3376 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003377 if(psrch_inf->smallBuf)
3378 cifs_small_buf_release(
3379 psrch_inf->ntwrk_buf_start);
3380 else
3381 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 psrch_inf->srch_entries_start = response_data;
3383 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003384 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 if(parms->EndofSearch)
3386 psrch_inf->endOfSearch = TRUE;
3387 else
3388 psrch_inf->endOfSearch = FALSE;
3389
3390 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3391 psrch_inf->index_of_last_entry +=
3392 psrch_inf->entries_in_buffer;
3393/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3394
3395 /* BB fixme add unlock here */
3396 }
3397
3398 }
3399
3400 /* BB On error, should we leave previous search buf (and count and
3401 last entry fields) intact or free the previous one? */
3402
3403 /* Note: On -EAGAIN error only caller can retry on handle based calls
3404 since file handle passed in no longer valid */
3405FNext2_err_exit:
3406 if (rc != 0)
3407 cifs_buf_release(pSMB);
3408
3409 return rc;
3410}
3411
3412int
3413CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3414{
3415 int rc = 0;
3416 FINDCLOSE_REQ *pSMB = NULL;
3417 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3418 int bytes_returned;
3419
3420 cFYI(1, ("In CIFSSMBFindClose"));
3421 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3422
3423 /* no sense returning error if session restarted
3424 as file handle has been closed */
3425 if(rc == -EAGAIN)
3426 return 0;
3427 if (rc)
3428 return rc;
3429
3430 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3431 pSMB->FileID = searchHandle;
3432 pSMB->ByteCount = 0;
3433 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3434 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3435 if (rc) {
3436 cERROR(1, ("Send error in FindClose = %d", rc));
3437 }
Steve Frencha4544342005-08-24 13:59:35 -07003438 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 cifs_small_buf_release(pSMB);
3440
3441 /* Since session is dead, search handle closed on server already */
3442 if (rc == -EAGAIN)
3443 rc = 0;
3444
3445 return rc;
3446}
3447
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448int
3449CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3450 const unsigned char *searchName,
3451 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003452 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453{
3454 int rc = 0;
3455 TRANSACTION2_QPI_REQ *pSMB = NULL;
3456 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3457 int name_len, bytes_returned;
3458 __u16 params, byte_count;
3459
3460 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3461 if(tcon == NULL)
3462 return -ENODEV;
3463
3464GetInodeNumberRetry:
3465 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3466 (void **) &pSMBr);
3467 if (rc)
3468 return rc;
3469
3470
3471 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3472 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003473 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003474 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 name_len++; /* trailing null */
3476 name_len *= 2;
3477 } else { /* BB improve the check for buffer overruns BB */
3478 name_len = strnlen(searchName, PATH_MAX);
3479 name_len++; /* trailing null */
3480 strncpy(pSMB->FileName, searchName, name_len);
3481 }
3482
3483 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3484 pSMB->TotalDataCount = 0;
3485 pSMB->MaxParameterCount = cpu_to_le16(2);
3486 /* BB find exact max data count below from sess structure BB */
3487 pSMB->MaxDataCount = cpu_to_le16(4000);
3488 pSMB->MaxSetupCount = 0;
3489 pSMB->Reserved = 0;
3490 pSMB->Flags = 0;
3491 pSMB->Timeout = 0;
3492 pSMB->Reserved2 = 0;
3493 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3494 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3495 pSMB->DataCount = 0;
3496 pSMB->DataOffset = 0;
3497 pSMB->SetupCount = 1;
3498 pSMB->Reserved3 = 0;
3499 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3500 byte_count = params + 1 /* pad */ ;
3501 pSMB->TotalParameterCount = cpu_to_le16(params);
3502 pSMB->ParameterCount = pSMB->TotalParameterCount;
3503 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3504 pSMB->Reserved4 = 0;
3505 pSMB->hdr.smb_buf_length += byte_count;
3506 pSMB->ByteCount = cpu_to_le16(byte_count);
3507
3508 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3509 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3510 if (rc) {
3511 cFYI(1, ("error %d in QueryInternalInfo", rc));
3512 } else {
3513 /* decode response */
3514 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3515 if (rc || (pSMBr->ByteCount < 2))
3516 /* BB also check enough total bytes returned */
3517 /* If rc should we check for EOPNOSUPP and
3518 disable the srvino flag? or in caller? */
3519 rc = -EIO; /* bad smb */
3520 else {
3521 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3522 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3523 struct file_internal_info * pfinfo;
3524 /* BB Do we need a cast or hash here ? */
3525 if(count < 8) {
3526 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3527 rc = -EIO;
3528 goto GetInodeNumOut;
3529 }
3530 pfinfo = (struct file_internal_info *)
3531 (data_offset + (char *) &pSMBr->hdr.Protocol);
3532 *inode_number = pfinfo->UniqueId;
3533 }
3534 }
3535GetInodeNumOut:
3536 cifs_buf_release(pSMB);
3537 if (rc == -EAGAIN)
3538 goto GetInodeNumberRetry;
3539 return rc;
3540}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541
3542int
3543CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3544 const unsigned char *searchName,
3545 unsigned char **targetUNCs,
3546 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003547 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548{
3549/* TRANS2_GET_DFS_REFERRAL */
3550 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3551 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3552 struct dfs_referral_level_3 * referrals = NULL;
3553 int rc = 0;
3554 int bytes_returned;
3555 int name_len;
3556 unsigned int i;
3557 char * temp;
3558 __u16 params, byte_count;
3559 *number_of_UNC_in_array = 0;
3560 *targetUNCs = NULL;
3561
3562 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3563 if (ses == NULL)
3564 return -ENODEV;
3565getDFSRetry:
3566 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3567 (void **) &pSMBr);
3568 if (rc)
3569 return rc;
Steve French1982c342005-08-17 12:38:22 -07003570
3571 /* server pointer checked in called function,
3572 but should never be null here anyway */
3573 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 pSMB->hdr.Tid = ses->ipc_tid;
3575 pSMB->hdr.Uid = ses->Suid;
3576 if (ses->capabilities & CAP_STATUS32) {
3577 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3578 }
3579 if (ses->capabilities & CAP_DFS) {
3580 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3581 }
3582
3583 if (ses->capabilities & CAP_UNICODE) {
3584 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3585 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003586 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003587 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 name_len++; /* trailing null */
3589 name_len *= 2;
3590 } else { /* BB improve the check for buffer overruns BB */
3591 name_len = strnlen(searchName, PATH_MAX);
3592 name_len++; /* trailing null */
3593 strncpy(pSMB->RequestFileName, searchName, name_len);
3594 }
3595
3596 params = 2 /* level */ + name_len /*includes null */ ;
3597 pSMB->TotalDataCount = 0;
3598 pSMB->DataCount = 0;
3599 pSMB->DataOffset = 0;
3600 pSMB->MaxParameterCount = 0;
3601 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3602 pSMB->MaxSetupCount = 0;
3603 pSMB->Reserved = 0;
3604 pSMB->Flags = 0;
3605 pSMB->Timeout = 0;
3606 pSMB->Reserved2 = 0;
3607 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3608 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3609 pSMB->SetupCount = 1;
3610 pSMB->Reserved3 = 0;
3611 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3612 byte_count = params + 3 /* pad */ ;
3613 pSMB->ParameterCount = cpu_to_le16(params);
3614 pSMB->TotalParameterCount = pSMB->ParameterCount;
3615 pSMB->MaxReferralLevel = cpu_to_le16(3);
3616 pSMB->hdr.smb_buf_length += byte_count;
3617 pSMB->ByteCount = cpu_to_le16(byte_count);
3618
3619 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3620 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3621 if (rc) {
3622 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3623 } else { /* decode response */
3624/* BB Add logic to parse referrals here */
3625 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3626
3627 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3628 rc = -EIO; /* bad smb */
3629 else {
3630 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3631 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3632
3633 cFYI(1,
3634 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3635 pSMBr->ByteCount, data_offset));
3636 referrals =
3637 (struct dfs_referral_level_3 *)
3638 (8 /* sizeof start of data block */ +
3639 data_offset +
3640 (char *) &pSMBr->hdr.Protocol);
3641 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",
3642 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)));
3643 /* BB This field is actually two bytes in from start of
3644 data block so we could do safety check that DataBlock
3645 begins at address of pSMBr->NumberOfReferrals */
3646 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3647
3648 /* BB Fix below so can return more than one referral */
3649 if(*number_of_UNC_in_array > 1)
3650 *number_of_UNC_in_array = 1;
3651
3652 /* get the length of the strings describing refs */
3653 name_len = 0;
3654 for(i=0;i<*number_of_UNC_in_array;i++) {
3655 /* make sure that DfsPathOffset not past end */
3656 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3657 if (offset > data_count) {
3658 /* if invalid referral, stop here and do
3659 not try to copy any more */
3660 *number_of_UNC_in_array = i;
3661 break;
3662 }
3663 temp = ((char *)referrals) + offset;
3664
3665 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3666 name_len += UniStrnlen((wchar_t *)temp,data_count);
3667 } else {
3668 name_len += strnlen(temp,data_count);
3669 }
3670 referrals++;
3671 /* BB add check that referral pointer does not fall off end PDU */
3672
3673 }
3674 /* BB add check for name_len bigger than bcc */
3675 *targetUNCs =
3676 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3677 if(*targetUNCs == NULL) {
3678 rc = -ENOMEM;
3679 goto GetDFSRefExit;
3680 }
3681 /* copy the ref strings */
3682 referrals =
3683 (struct dfs_referral_level_3 *)
3684 (8 /* sizeof data hdr */ +
3685 data_offset +
3686 (char *) &pSMBr->hdr.Protocol);
3687
3688 for(i=0;i<*number_of_UNC_in_array;i++) {
3689 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3690 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3691 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003692 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 } else {
3694 strncpy(*targetUNCs,temp,name_len);
3695 }
3696 /* BB update target_uncs pointers */
3697 referrals++;
3698 }
3699 temp = *targetUNCs;
3700 temp[name_len] = 0;
3701 }
3702
3703 }
3704GetDFSRefExit:
3705 if (pSMB)
3706 cifs_buf_release(pSMB);
3707
3708 if (rc == -EAGAIN)
3709 goto getDFSRetry;
3710
3711 return rc;
3712}
3713
Steve French20962432005-09-21 22:05:57 -07003714/* Query File System Info such as free space to old servers such as Win 9x */
3715int
3716SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3717{
3718/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3719 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3720 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3721 FILE_SYSTEM_ALLOC_INFO *response_data;
3722 int rc = 0;
3723 int bytes_returned = 0;
3724 __u16 params, byte_count;
3725
3726 cFYI(1, ("OldQFSInfo"));
3727oldQFSInfoRetry:
3728 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3729 (void **) &pSMBr);
3730 if (rc)
3731 return rc;
3732 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3733 (void **) &pSMBr);
3734 if (rc)
3735 return rc;
3736
3737 params = 2; /* level */
3738 pSMB->TotalDataCount = 0;
3739 pSMB->MaxParameterCount = cpu_to_le16(2);
3740 pSMB->MaxDataCount = cpu_to_le16(1000);
3741 pSMB->MaxSetupCount = 0;
3742 pSMB->Reserved = 0;
3743 pSMB->Flags = 0;
3744 pSMB->Timeout = 0;
3745 pSMB->Reserved2 = 0;
3746 byte_count = params + 1 /* pad */ ;
3747 pSMB->TotalParameterCount = cpu_to_le16(params);
3748 pSMB->ParameterCount = pSMB->TotalParameterCount;
3749 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3750 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3751 pSMB->DataCount = 0;
3752 pSMB->DataOffset = 0;
3753 pSMB->SetupCount = 1;
3754 pSMB->Reserved3 = 0;
3755 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3756 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3757 pSMB->hdr.smb_buf_length += byte_count;
3758 pSMB->ByteCount = cpu_to_le16(byte_count);
3759
3760 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3761 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3762 if (rc) {
3763 cFYI(1, ("Send error in QFSInfo = %d", rc));
3764 } else { /* decode response */
3765 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3766
3767 if (rc || (pSMBr->ByteCount < 18))
3768 rc = -EIO; /* bad smb */
3769 else {
3770 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3771 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3772 pSMBr->ByteCount, data_offset));
3773
3774 response_data =
3775 (FILE_SYSTEM_ALLOC_INFO *)
3776 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3777 FSData->f_bsize =
3778 le16_to_cpu(response_data->BytesPerSector) *
3779 le32_to_cpu(response_data->
3780 SectorsPerAllocationUnit);
3781 FSData->f_blocks =
3782 le32_to_cpu(response_data->TotalAllocationUnits);
3783 FSData->f_bfree = FSData->f_bavail =
3784 le32_to_cpu(response_data->FreeAllocationUnits);
3785 cFYI(1,
3786 ("Blocks: %lld Free: %lld Block size %ld",
3787 (unsigned long long)FSData->f_blocks,
3788 (unsigned long long)FSData->f_bfree,
3789 FSData->f_bsize));
3790 }
3791 }
3792 cifs_buf_release(pSMB);
3793
3794 if (rc == -EAGAIN)
3795 goto oldQFSInfoRetry;
3796
3797 return rc;
3798}
3799
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800int
Steve French737b7582005-04-28 22:41:06 -07003801CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802{
3803/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3804 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3805 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3806 FILE_SYSTEM_INFO *response_data;
3807 int rc = 0;
3808 int bytes_returned = 0;
3809 __u16 params, byte_count;
3810
3811 cFYI(1, ("In QFSInfo"));
3812QFSInfoRetry:
3813 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3814 (void **) &pSMBr);
3815 if (rc)
3816 return rc;
3817
3818 params = 2; /* level */
3819 pSMB->TotalDataCount = 0;
3820 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003821 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 pSMB->MaxSetupCount = 0;
3823 pSMB->Reserved = 0;
3824 pSMB->Flags = 0;
3825 pSMB->Timeout = 0;
3826 pSMB->Reserved2 = 0;
3827 byte_count = params + 1 /* pad */ ;
3828 pSMB->TotalParameterCount = cpu_to_le16(params);
3829 pSMB->ParameterCount = pSMB->TotalParameterCount;
3830 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3831 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3832 pSMB->DataCount = 0;
3833 pSMB->DataOffset = 0;
3834 pSMB->SetupCount = 1;
3835 pSMB->Reserved3 = 0;
3836 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3837 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3838 pSMB->hdr.smb_buf_length += byte_count;
3839 pSMB->ByteCount = cpu_to_le16(byte_count);
3840
3841 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3842 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3843 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003844 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 } else { /* decode response */
3846 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3847
Steve French20962432005-09-21 22:05:57 -07003848 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 rc = -EIO; /* bad smb */
3850 else {
3851 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852
3853 response_data =
3854 (FILE_SYSTEM_INFO
3855 *) (((char *) &pSMBr->hdr.Protocol) +
3856 data_offset);
3857 FSData->f_bsize =
3858 le32_to_cpu(response_data->BytesPerSector) *
3859 le32_to_cpu(response_data->
3860 SectorsPerAllocationUnit);
3861 FSData->f_blocks =
3862 le64_to_cpu(response_data->TotalAllocationUnits);
3863 FSData->f_bfree = FSData->f_bavail =
3864 le64_to_cpu(response_data->FreeAllocationUnits);
3865 cFYI(1,
3866 ("Blocks: %lld Free: %lld Block size %ld",
3867 (unsigned long long)FSData->f_blocks,
3868 (unsigned long long)FSData->f_bfree,
3869 FSData->f_bsize));
3870 }
3871 }
3872 cifs_buf_release(pSMB);
3873
3874 if (rc == -EAGAIN)
3875 goto QFSInfoRetry;
3876
3877 return rc;
3878}
3879
3880int
Steve French737b7582005-04-28 22:41:06 -07003881CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882{
3883/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3884 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3885 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3886 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3887 int rc = 0;
3888 int bytes_returned = 0;
3889 __u16 params, byte_count;
3890
3891 cFYI(1, ("In QFSAttributeInfo"));
3892QFSAttributeRetry:
3893 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3894 (void **) &pSMBr);
3895 if (rc)
3896 return rc;
3897
3898 params = 2; /* level */
3899 pSMB->TotalDataCount = 0;
3900 pSMB->MaxParameterCount = cpu_to_le16(2);
3901 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3902 pSMB->MaxSetupCount = 0;
3903 pSMB->Reserved = 0;
3904 pSMB->Flags = 0;
3905 pSMB->Timeout = 0;
3906 pSMB->Reserved2 = 0;
3907 byte_count = params + 1 /* pad */ ;
3908 pSMB->TotalParameterCount = cpu_to_le16(params);
3909 pSMB->ParameterCount = pSMB->TotalParameterCount;
3910 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3911 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3912 pSMB->DataCount = 0;
3913 pSMB->DataOffset = 0;
3914 pSMB->SetupCount = 1;
3915 pSMB->Reserved3 = 0;
3916 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3917 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3918 pSMB->hdr.smb_buf_length += byte_count;
3919 pSMB->ByteCount = cpu_to_le16(byte_count);
3920
3921 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3922 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3923 if (rc) {
3924 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3925 } else { /* decode response */
3926 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3927
3928 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3929 rc = -EIO; /* bad smb */
3930 } else {
3931 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3932 response_data =
3933 (FILE_SYSTEM_ATTRIBUTE_INFO
3934 *) (((char *) &pSMBr->hdr.Protocol) +
3935 data_offset);
3936 memcpy(&tcon->fsAttrInfo, response_data,
3937 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3938 }
3939 }
3940 cifs_buf_release(pSMB);
3941
3942 if (rc == -EAGAIN)
3943 goto QFSAttributeRetry;
3944
3945 return rc;
3946}
3947
3948int
Steve French737b7582005-04-28 22:41:06 -07003949CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950{
3951/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3952 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3953 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3954 FILE_SYSTEM_DEVICE_INFO *response_data;
3955 int rc = 0;
3956 int bytes_returned = 0;
3957 __u16 params, byte_count;
3958
3959 cFYI(1, ("In QFSDeviceInfo"));
3960QFSDeviceRetry:
3961 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3962 (void **) &pSMBr);
3963 if (rc)
3964 return rc;
3965
3966 params = 2; /* level */
3967 pSMB->TotalDataCount = 0;
3968 pSMB->MaxParameterCount = cpu_to_le16(2);
3969 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3970 pSMB->MaxSetupCount = 0;
3971 pSMB->Reserved = 0;
3972 pSMB->Flags = 0;
3973 pSMB->Timeout = 0;
3974 pSMB->Reserved2 = 0;
3975 byte_count = params + 1 /* pad */ ;
3976 pSMB->TotalParameterCount = cpu_to_le16(params);
3977 pSMB->ParameterCount = pSMB->TotalParameterCount;
3978 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3979 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3980
3981 pSMB->DataCount = 0;
3982 pSMB->DataOffset = 0;
3983 pSMB->SetupCount = 1;
3984 pSMB->Reserved3 = 0;
3985 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3986 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3987 pSMB->hdr.smb_buf_length += byte_count;
3988 pSMB->ByteCount = cpu_to_le16(byte_count);
3989
3990 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3991 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3992 if (rc) {
3993 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3994 } else { /* decode response */
3995 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3996
3997 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3998 rc = -EIO; /* bad smb */
3999 else {
4000 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4001 response_data =
Steve French737b7582005-04-28 22:41:06 -07004002 (FILE_SYSTEM_DEVICE_INFO *)
4003 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 data_offset);
4005 memcpy(&tcon->fsDevInfo, response_data,
4006 sizeof (FILE_SYSTEM_DEVICE_INFO));
4007 }
4008 }
4009 cifs_buf_release(pSMB);
4010
4011 if (rc == -EAGAIN)
4012 goto QFSDeviceRetry;
4013
4014 return rc;
4015}
4016
4017int
Steve French737b7582005-04-28 22:41:06 -07004018CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019{
4020/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4021 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4022 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4023 FILE_SYSTEM_UNIX_INFO *response_data;
4024 int rc = 0;
4025 int bytes_returned = 0;
4026 __u16 params, byte_count;
4027
4028 cFYI(1, ("In QFSUnixInfo"));
4029QFSUnixRetry:
4030 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4031 (void **) &pSMBr);
4032 if (rc)
4033 return rc;
4034
4035 params = 2; /* level */
4036 pSMB->TotalDataCount = 0;
4037 pSMB->DataCount = 0;
4038 pSMB->DataOffset = 0;
4039 pSMB->MaxParameterCount = cpu_to_le16(2);
4040 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4041 pSMB->MaxSetupCount = 0;
4042 pSMB->Reserved = 0;
4043 pSMB->Flags = 0;
4044 pSMB->Timeout = 0;
4045 pSMB->Reserved2 = 0;
4046 byte_count = params + 1 /* pad */ ;
4047 pSMB->ParameterCount = cpu_to_le16(params);
4048 pSMB->TotalParameterCount = pSMB->ParameterCount;
4049 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4050 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4051 pSMB->SetupCount = 1;
4052 pSMB->Reserved3 = 0;
4053 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4054 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4055 pSMB->hdr.smb_buf_length += byte_count;
4056 pSMB->ByteCount = cpu_to_le16(byte_count);
4057
4058 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4059 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4060 if (rc) {
4061 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4062 } else { /* decode response */
4063 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4064
4065 if (rc || (pSMBr->ByteCount < 13)) {
4066 rc = -EIO; /* bad smb */
4067 } else {
4068 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4069 response_data =
4070 (FILE_SYSTEM_UNIX_INFO
4071 *) (((char *) &pSMBr->hdr.Protocol) +
4072 data_offset);
4073 memcpy(&tcon->fsUnixInfo, response_data,
4074 sizeof (FILE_SYSTEM_UNIX_INFO));
4075 }
4076 }
4077 cifs_buf_release(pSMB);
4078
4079 if (rc == -EAGAIN)
4080 goto QFSUnixRetry;
4081
4082
4083 return rc;
4084}
4085
Jeremy Allisonac670552005-06-22 17:26:35 -07004086int
Steve French45abc6e2005-06-23 13:42:03 -05004087CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004088{
4089/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4090 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4091 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4092 int rc = 0;
4093 int bytes_returned = 0;
4094 __u16 params, param_offset, offset, byte_count;
4095
4096 cFYI(1, ("In SETFSUnixInfo"));
4097SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004098 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004099 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4100 (void **) &pSMBr);
4101 if (rc)
4102 return rc;
4103
4104 params = 4; /* 2 bytes zero followed by info level. */
4105 pSMB->MaxSetupCount = 0;
4106 pSMB->Reserved = 0;
4107 pSMB->Flags = 0;
4108 pSMB->Timeout = 0;
4109 pSMB->Reserved2 = 0;
4110 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4111 offset = param_offset + params;
4112
4113 pSMB->MaxParameterCount = cpu_to_le16(4);
4114 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4115 pSMB->SetupCount = 1;
4116 pSMB->Reserved3 = 0;
4117 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4118 byte_count = 1 /* pad */ + params + 12;
4119
4120 pSMB->DataCount = cpu_to_le16(12);
4121 pSMB->ParameterCount = cpu_to_le16(params);
4122 pSMB->TotalDataCount = pSMB->DataCount;
4123 pSMB->TotalParameterCount = pSMB->ParameterCount;
4124 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4125 pSMB->DataOffset = cpu_to_le16(offset);
4126
4127 /* Params. */
4128 pSMB->FileNum = 0;
4129 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4130
4131 /* Data. */
4132 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4133 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4134 pSMB->ClientUnixCap = cpu_to_le64(cap);
4135
4136 pSMB->hdr.smb_buf_length += byte_count;
4137 pSMB->ByteCount = cpu_to_le16(byte_count);
4138
4139 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4140 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4141 if (rc) {
4142 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4143 } else { /* decode response */
4144 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4145 if (rc) {
4146 rc = -EIO; /* bad smb */
4147 }
4148 }
4149 cifs_buf_release(pSMB);
4150
4151 if (rc == -EAGAIN)
4152 goto SETFSUnixRetry;
4153
4154 return rc;
4155}
4156
4157
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158
4159int
4160CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004161 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162{
4163/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4164 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4165 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4166 FILE_SYSTEM_POSIX_INFO *response_data;
4167 int rc = 0;
4168 int bytes_returned = 0;
4169 __u16 params, byte_count;
4170
4171 cFYI(1, ("In QFSPosixInfo"));
4172QFSPosixRetry:
4173 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4174 (void **) &pSMBr);
4175 if (rc)
4176 return rc;
4177
4178 params = 2; /* level */
4179 pSMB->TotalDataCount = 0;
4180 pSMB->DataCount = 0;
4181 pSMB->DataOffset = 0;
4182 pSMB->MaxParameterCount = cpu_to_le16(2);
4183 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4184 pSMB->MaxSetupCount = 0;
4185 pSMB->Reserved = 0;
4186 pSMB->Flags = 0;
4187 pSMB->Timeout = 0;
4188 pSMB->Reserved2 = 0;
4189 byte_count = params + 1 /* pad */ ;
4190 pSMB->ParameterCount = cpu_to_le16(params);
4191 pSMB->TotalParameterCount = pSMB->ParameterCount;
4192 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4193 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4194 pSMB->SetupCount = 1;
4195 pSMB->Reserved3 = 0;
4196 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4197 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4198 pSMB->hdr.smb_buf_length += byte_count;
4199 pSMB->ByteCount = cpu_to_le16(byte_count);
4200
4201 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4202 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4203 if (rc) {
4204 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4205 } else { /* decode response */
4206 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4207
4208 if (rc || (pSMBr->ByteCount < 13)) {
4209 rc = -EIO; /* bad smb */
4210 } else {
4211 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4212 response_data =
4213 (FILE_SYSTEM_POSIX_INFO
4214 *) (((char *) &pSMBr->hdr.Protocol) +
4215 data_offset);
4216 FSData->f_bsize =
4217 le32_to_cpu(response_data->BlockSize);
4218 FSData->f_blocks =
4219 le64_to_cpu(response_data->TotalBlocks);
4220 FSData->f_bfree =
4221 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004222 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 FSData->f_bavail = FSData->f_bfree;
4224 } else {
4225 FSData->f_bavail =
4226 le64_to_cpu(response_data->UserBlocksAvail);
4227 }
Steve French70ca7342005-09-22 16:32:06 -07004228 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 FSData->f_files =
4230 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004231 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 FSData->f_ffree =
4233 le64_to_cpu(response_data->FreeFileNodes);
4234 }
4235 }
4236 cifs_buf_release(pSMB);
4237
4238 if (rc == -EAGAIN)
4239 goto QFSPosixRetry;
4240
4241 return rc;
4242}
4243
4244
4245/* We can not use write of zero bytes trick to
4246 set file size due to need for large file support. Also note that
4247 this SetPathInfo is preferred to SetFileInfo based method in next
4248 routine which is only needed to work around a sharing violation bug
4249 in Samba which this routine can run into */
4250
4251int
4252CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004253 __u64 size, int SetAllocation,
4254 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255{
4256 struct smb_com_transaction2_spi_req *pSMB = NULL;
4257 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4258 struct file_end_of_file_info *parm_data;
4259 int name_len;
4260 int rc = 0;
4261 int bytes_returned = 0;
4262 __u16 params, byte_count, data_count, param_offset, offset;
4263
4264 cFYI(1, ("In SetEOF"));
4265SetEOFRetry:
4266 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4267 (void **) &pSMBr);
4268 if (rc)
4269 return rc;
4270
4271 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4272 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004273 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004274 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 name_len++; /* trailing null */
4276 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004277 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 name_len = strnlen(fileName, PATH_MAX);
4279 name_len++; /* trailing null */
4280 strncpy(pSMB->FileName, fileName, name_len);
4281 }
4282 params = 6 + name_len;
4283 data_count = sizeof (struct file_end_of_file_info);
4284 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004285 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 pSMB->MaxSetupCount = 0;
4287 pSMB->Reserved = 0;
4288 pSMB->Flags = 0;
4289 pSMB->Timeout = 0;
4290 pSMB->Reserved2 = 0;
4291 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4292 InformationLevel) - 4;
4293 offset = param_offset + params;
4294 if(SetAllocation) {
4295 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4296 pSMB->InformationLevel =
4297 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4298 else
4299 pSMB->InformationLevel =
4300 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4301 } else /* Set File Size */ {
4302 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4303 pSMB->InformationLevel =
4304 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4305 else
4306 pSMB->InformationLevel =
4307 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4308 }
4309
4310 parm_data =
4311 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4312 offset);
4313 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4314 pSMB->DataOffset = cpu_to_le16(offset);
4315 pSMB->SetupCount = 1;
4316 pSMB->Reserved3 = 0;
4317 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4318 byte_count = 3 /* pad */ + params + data_count;
4319 pSMB->DataCount = cpu_to_le16(data_count);
4320 pSMB->TotalDataCount = pSMB->DataCount;
4321 pSMB->ParameterCount = cpu_to_le16(params);
4322 pSMB->TotalParameterCount = pSMB->ParameterCount;
4323 pSMB->Reserved4 = 0;
4324 pSMB->hdr.smb_buf_length += byte_count;
4325 parm_data->FileSize = cpu_to_le64(size);
4326 pSMB->ByteCount = cpu_to_le16(byte_count);
4327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4328 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4329 if (rc) {
4330 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4331 }
4332
4333 cifs_buf_release(pSMB);
4334
4335 if (rc == -EAGAIN)
4336 goto SetEOFRetry;
4337
4338 return rc;
4339}
4340
4341int
4342CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4343 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4344{
4345 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4346 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4347 char *data_offset;
4348 struct file_end_of_file_info *parm_data;
4349 int rc = 0;
4350 int bytes_returned = 0;
4351 __u16 params, param_offset, offset, byte_count, count;
4352
4353 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4354 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004355 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4356
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 if (rc)
4358 return rc;
4359
Steve Frenchcd634992005-04-28 22:41:10 -07004360 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4361
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4363 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4364
4365 params = 6;
4366 pSMB->MaxSetupCount = 0;
4367 pSMB->Reserved = 0;
4368 pSMB->Flags = 0;
4369 pSMB->Timeout = 0;
4370 pSMB->Reserved2 = 0;
4371 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4372 offset = param_offset + params;
4373
4374 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4375
4376 count = sizeof(struct file_end_of_file_info);
4377 pSMB->MaxParameterCount = cpu_to_le16(2);
4378 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4379 pSMB->SetupCount = 1;
4380 pSMB->Reserved3 = 0;
4381 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4382 byte_count = 3 /* pad */ + params + count;
4383 pSMB->DataCount = cpu_to_le16(count);
4384 pSMB->ParameterCount = cpu_to_le16(params);
4385 pSMB->TotalDataCount = pSMB->DataCount;
4386 pSMB->TotalParameterCount = pSMB->ParameterCount;
4387 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4388 parm_data =
4389 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4390 offset);
4391 pSMB->DataOffset = cpu_to_le16(offset);
4392 parm_data->FileSize = cpu_to_le64(size);
4393 pSMB->Fid = fid;
4394 if(SetAllocation) {
4395 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4396 pSMB->InformationLevel =
4397 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4398 else
4399 pSMB->InformationLevel =
4400 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4401 } else /* Set File Size */ {
4402 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4403 pSMB->InformationLevel =
4404 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4405 else
4406 pSMB->InformationLevel =
4407 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4408 }
4409 pSMB->Reserved4 = 0;
4410 pSMB->hdr.smb_buf_length += byte_count;
4411 pSMB->ByteCount = cpu_to_le16(byte_count);
4412 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4413 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4414 if (rc) {
4415 cFYI(1,
4416 ("Send error in SetFileInfo (SetFileSize) = %d",
4417 rc));
4418 }
4419
4420 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004421 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422
4423 /* Note: On -EAGAIN error only caller can retry on handle based calls
4424 since file handle passed in no longer valid */
4425
4426 return rc;
4427}
4428
4429/* Some legacy servers such as NT4 require that the file times be set on
4430 an open handle, rather than by pathname - this is awkward due to
4431 potential access conflicts on the open, but it is unavoidable for these
4432 old servers since the only other choice is to go from 100 nanosecond DCE
4433 time and resort to the original setpathinfo level which takes the ancient
4434 DOS time format with 2 second granularity */
4435int
4436CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4437 __u16 fid)
4438{
4439 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4440 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4441 char *data_offset;
4442 int rc = 0;
4443 int bytes_returned = 0;
4444 __u16 params, param_offset, offset, byte_count, count;
4445
4446 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004447 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4448
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 if (rc)
4450 return rc;
4451
Steve Frenchcd634992005-04-28 22:41:10 -07004452 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4453
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 /* At this point there is no need to override the current pid
4455 with the pid of the opener, but that could change if we someday
4456 use an existing handle (rather than opening one on the fly) */
4457 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4458 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4459
4460 params = 6;
4461 pSMB->MaxSetupCount = 0;
4462 pSMB->Reserved = 0;
4463 pSMB->Flags = 0;
4464 pSMB->Timeout = 0;
4465 pSMB->Reserved2 = 0;
4466 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4467 offset = param_offset + params;
4468
4469 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4470
4471 count = sizeof (FILE_BASIC_INFO);
4472 pSMB->MaxParameterCount = cpu_to_le16(2);
4473 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4474 pSMB->SetupCount = 1;
4475 pSMB->Reserved3 = 0;
4476 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4477 byte_count = 3 /* pad */ + params + count;
4478 pSMB->DataCount = cpu_to_le16(count);
4479 pSMB->ParameterCount = cpu_to_le16(params);
4480 pSMB->TotalDataCount = pSMB->DataCount;
4481 pSMB->TotalParameterCount = pSMB->ParameterCount;
4482 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4483 pSMB->DataOffset = cpu_to_le16(offset);
4484 pSMB->Fid = fid;
4485 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4486 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4487 else
4488 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4489 pSMB->Reserved4 = 0;
4490 pSMB->hdr.smb_buf_length += byte_count;
4491 pSMB->ByteCount = cpu_to_le16(byte_count);
4492 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4493 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4494 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4495 if (rc) {
4496 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4497 }
4498
Steve Frenchcd634992005-04-28 22:41:10 -07004499 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500
4501 /* Note: On -EAGAIN error only caller can retry on handle based calls
4502 since file handle passed in no longer valid */
4503
4504 return rc;
4505}
4506
4507
4508int
4509CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4510 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004511 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512{
4513 TRANSACTION2_SPI_REQ *pSMB = NULL;
4514 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4515 int name_len;
4516 int rc = 0;
4517 int bytes_returned = 0;
4518 char *data_offset;
4519 __u16 params, param_offset, offset, byte_count, count;
4520
4521 cFYI(1, ("In SetTimes"));
4522
4523SetTimesRetry:
4524 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4525 (void **) &pSMBr);
4526 if (rc)
4527 return rc;
4528
4529 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4530 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004531 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004532 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 name_len++; /* trailing null */
4534 name_len *= 2;
4535 } else { /* BB improve the check for buffer overruns BB */
4536 name_len = strnlen(fileName, PATH_MAX);
4537 name_len++; /* trailing null */
4538 strncpy(pSMB->FileName, fileName, name_len);
4539 }
4540
4541 params = 6 + name_len;
4542 count = sizeof (FILE_BASIC_INFO);
4543 pSMB->MaxParameterCount = cpu_to_le16(2);
4544 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4545 pSMB->MaxSetupCount = 0;
4546 pSMB->Reserved = 0;
4547 pSMB->Flags = 0;
4548 pSMB->Timeout = 0;
4549 pSMB->Reserved2 = 0;
4550 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4551 InformationLevel) - 4;
4552 offset = param_offset + params;
4553 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4554 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4555 pSMB->DataOffset = cpu_to_le16(offset);
4556 pSMB->SetupCount = 1;
4557 pSMB->Reserved3 = 0;
4558 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4559 byte_count = 3 /* pad */ + params + count;
4560
4561 pSMB->DataCount = cpu_to_le16(count);
4562 pSMB->ParameterCount = cpu_to_le16(params);
4563 pSMB->TotalDataCount = pSMB->DataCount;
4564 pSMB->TotalParameterCount = pSMB->ParameterCount;
4565 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4566 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4567 else
4568 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4569 pSMB->Reserved4 = 0;
4570 pSMB->hdr.smb_buf_length += byte_count;
4571 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4572 pSMB->ByteCount = cpu_to_le16(byte_count);
4573 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4574 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4575 if (rc) {
4576 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4577 }
4578
4579 cifs_buf_release(pSMB);
4580
4581 if (rc == -EAGAIN)
4582 goto SetTimesRetry;
4583
4584 return rc;
4585}
4586
4587/* Can not be used to set time stamps yet (due to old DOS time format) */
4588/* Can be used to set attributes */
4589#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4590 handling it anyway and NT4 was what we thought it would be needed for
4591 Do not delete it until we prove whether needed for Win9x though */
4592int
4593CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4594 __u16 dos_attrs, const struct nls_table *nls_codepage)
4595{
4596 SETATTR_REQ *pSMB = NULL;
4597 SETATTR_RSP *pSMBr = NULL;
4598 int rc = 0;
4599 int bytes_returned;
4600 int name_len;
4601
4602 cFYI(1, ("In SetAttrLegacy"));
4603
4604SetAttrLgcyRetry:
4605 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4606 (void **) &pSMBr);
4607 if (rc)
4608 return rc;
4609
4610 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4611 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004612 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 PATH_MAX, nls_codepage);
4614 name_len++; /* trailing null */
4615 name_len *= 2;
4616 } else { /* BB improve the check for buffer overruns BB */
4617 name_len = strnlen(fileName, PATH_MAX);
4618 name_len++; /* trailing null */
4619 strncpy(pSMB->fileName, fileName, name_len);
4620 }
4621 pSMB->attr = cpu_to_le16(dos_attrs);
4622 pSMB->BufferFormat = 0x04;
4623 pSMB->hdr.smb_buf_length += name_len + 1;
4624 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4625 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4626 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4627 if (rc) {
4628 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4629 }
4630
4631 cifs_buf_release(pSMB);
4632
4633 if (rc == -EAGAIN)
4634 goto SetAttrLgcyRetry;
4635
4636 return rc;
4637}
4638#endif /* temporarily unneeded SetAttr legacy function */
4639
4640int
4641CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004642 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4643 dev_t device, const struct nls_table *nls_codepage,
4644 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645{
4646 TRANSACTION2_SPI_REQ *pSMB = NULL;
4647 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4648 int name_len;
4649 int rc = 0;
4650 int bytes_returned = 0;
4651 FILE_UNIX_BASIC_INFO *data_offset;
4652 __u16 params, param_offset, offset, count, byte_count;
4653
4654 cFYI(1, ("In SetUID/GID/Mode"));
4655setPermsRetry:
4656 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4657 (void **) &pSMBr);
4658 if (rc)
4659 return rc;
4660
4661 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4662 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004663 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004664 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 name_len++; /* trailing null */
4666 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004667 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 name_len = strnlen(fileName, PATH_MAX);
4669 name_len++; /* trailing null */
4670 strncpy(pSMB->FileName, fileName, name_len);
4671 }
4672
4673 params = 6 + name_len;
4674 count = sizeof (FILE_UNIX_BASIC_INFO);
4675 pSMB->MaxParameterCount = cpu_to_le16(2);
4676 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4677 pSMB->MaxSetupCount = 0;
4678 pSMB->Reserved = 0;
4679 pSMB->Flags = 0;
4680 pSMB->Timeout = 0;
4681 pSMB->Reserved2 = 0;
4682 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4683 InformationLevel) - 4;
4684 offset = param_offset + params;
4685 data_offset =
4686 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4687 offset);
4688 memset(data_offset, 0, count);
4689 pSMB->DataOffset = cpu_to_le16(offset);
4690 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4691 pSMB->SetupCount = 1;
4692 pSMB->Reserved3 = 0;
4693 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4694 byte_count = 3 /* pad */ + params + count;
4695 pSMB->ParameterCount = cpu_to_le16(params);
4696 pSMB->DataCount = cpu_to_le16(count);
4697 pSMB->TotalParameterCount = pSMB->ParameterCount;
4698 pSMB->TotalDataCount = pSMB->DataCount;
4699 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4700 pSMB->Reserved4 = 0;
4701 pSMB->hdr.smb_buf_length += byte_count;
4702 data_offset->Uid = cpu_to_le64(uid);
4703 data_offset->Gid = cpu_to_le64(gid);
4704 /* better to leave device as zero when it is */
4705 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4706 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4707 data_offset->Permissions = cpu_to_le64(mode);
4708
4709 if(S_ISREG(mode))
4710 data_offset->Type = cpu_to_le32(UNIX_FILE);
4711 else if(S_ISDIR(mode))
4712 data_offset->Type = cpu_to_le32(UNIX_DIR);
4713 else if(S_ISLNK(mode))
4714 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4715 else if(S_ISCHR(mode))
4716 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4717 else if(S_ISBLK(mode))
4718 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4719 else if(S_ISFIFO(mode))
4720 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4721 else if(S_ISSOCK(mode))
4722 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4723
4724
4725 pSMB->ByteCount = cpu_to_le16(byte_count);
4726 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4727 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4728 if (rc) {
4729 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4730 }
4731
4732 if (pSMB)
4733 cifs_buf_release(pSMB);
4734 if (rc == -EAGAIN)
4735 goto setPermsRetry;
4736 return rc;
4737}
4738
4739int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004740 const int notify_subdirs, const __u16 netfid,
4741 __u32 filter, struct file * pfile, int multishot,
4742 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743{
4744 int rc = 0;
4745 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004746 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004747 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 int bytes_returned;
4749
4750 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4751 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4752 (void **) &pSMBr);
4753 if (rc)
4754 return rc;
4755
4756 pSMB->TotalParameterCount = 0 ;
4757 pSMB->TotalDataCount = 0;
4758 pSMB->MaxParameterCount = cpu_to_le32(2);
4759 /* BB find exact data count max from sess structure BB */
4760 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004761/* BB VERIFY verify which is correct for above BB */
4762 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4763 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4764
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 pSMB->MaxSetupCount = 4;
4766 pSMB->Reserved = 0;
4767 pSMB->ParameterOffset = 0;
4768 pSMB->DataCount = 0;
4769 pSMB->DataOffset = 0;
4770 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4771 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4772 pSMB->ParameterCount = pSMB->TotalParameterCount;
4773 if(notify_subdirs)
4774 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4775 pSMB->Reserved2 = 0;
4776 pSMB->CompletionFilter = cpu_to_le32(filter);
4777 pSMB->Fid = netfid; /* file handle always le */
4778 pSMB->ByteCount = 0;
4779
4780 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4781 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4782 if (rc) {
4783 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004784 } else {
4785 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004786 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004787 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004788 sizeof(struct dir_notify_req),
4789 GFP_KERNEL);
4790 if(dnotify_req) {
4791 dnotify_req->Pid = pSMB->hdr.Pid;
4792 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4793 dnotify_req->Mid = pSMB->hdr.Mid;
4794 dnotify_req->Tid = pSMB->hdr.Tid;
4795 dnotify_req->Uid = pSMB->hdr.Uid;
4796 dnotify_req->netfid = netfid;
4797 dnotify_req->pfile = pfile;
4798 dnotify_req->filter = filter;
4799 dnotify_req->multishot = multishot;
4800 spin_lock(&GlobalMid_Lock);
4801 list_add_tail(&dnotify_req->lhead,
4802 &GlobalDnotifyReqList);
4803 spin_unlock(&GlobalMid_Lock);
4804 } else
4805 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 }
4807 cifs_buf_release(pSMB);
4808 return rc;
4809}
4810#ifdef CONFIG_CIFS_XATTR
4811ssize_t
4812CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4813 const unsigned char *searchName,
4814 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004815 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816{
4817 /* BB assumes one setup word */
4818 TRANSACTION2_QPI_REQ *pSMB = NULL;
4819 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4820 int rc = 0;
4821 int bytes_returned;
4822 int name_len;
4823 struct fea * temp_fea;
4824 char * temp_ptr;
4825 __u16 params, byte_count;
4826
4827 cFYI(1, ("In Query All EAs path %s", searchName));
4828QAllEAsRetry:
4829 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4830 (void **) &pSMBr);
4831 if (rc)
4832 return rc;
4833
4834 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4835 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004836 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004837 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 name_len++; /* trailing null */
4839 name_len *= 2;
4840 } else { /* BB improve the check for buffer overruns BB */
4841 name_len = strnlen(searchName, PATH_MAX);
4842 name_len++; /* trailing null */
4843 strncpy(pSMB->FileName, searchName, name_len);
4844 }
4845
4846 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4847 pSMB->TotalDataCount = 0;
4848 pSMB->MaxParameterCount = cpu_to_le16(2);
4849 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4850 pSMB->MaxSetupCount = 0;
4851 pSMB->Reserved = 0;
4852 pSMB->Flags = 0;
4853 pSMB->Timeout = 0;
4854 pSMB->Reserved2 = 0;
4855 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4856 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4857 pSMB->DataCount = 0;
4858 pSMB->DataOffset = 0;
4859 pSMB->SetupCount = 1;
4860 pSMB->Reserved3 = 0;
4861 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4862 byte_count = params + 1 /* pad */ ;
4863 pSMB->TotalParameterCount = cpu_to_le16(params);
4864 pSMB->ParameterCount = pSMB->TotalParameterCount;
4865 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4866 pSMB->Reserved4 = 0;
4867 pSMB->hdr.smb_buf_length += byte_count;
4868 pSMB->ByteCount = cpu_to_le16(byte_count);
4869
4870 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4871 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4872 if (rc) {
4873 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4874 } else { /* decode response */
4875 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4876
4877 /* BB also check enough total bytes returned */
4878 /* BB we need to improve the validity checking
4879 of these trans2 responses */
4880 if (rc || (pSMBr->ByteCount < 4))
4881 rc = -EIO; /* bad smb */
4882 /* else if (pFindData){
4883 memcpy((char *) pFindData,
4884 (char *) &pSMBr->hdr.Protocol +
4885 data_offset, kl);
4886 }*/ else {
4887 /* check that length of list is not more than bcc */
4888 /* check that each entry does not go beyond length
4889 of list */
4890 /* check that each element of each entry does not
4891 go beyond end of list */
4892 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4893 struct fealist * ea_response_data;
4894 rc = 0;
4895 /* validate_trans2_offsets() */
4896 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4897 ea_response_data = (struct fealist *)
4898 (((char *) &pSMBr->hdr.Protocol) +
4899 data_offset);
4900 name_len = le32_to_cpu(ea_response_data->list_len);
4901 cFYI(1,("ea length %d", name_len));
4902 if(name_len <= 8) {
4903 /* returned EA size zeroed at top of function */
4904 cFYI(1,("empty EA list returned from server"));
4905 } else {
4906 /* account for ea list len */
4907 name_len -= 4;
4908 temp_fea = ea_response_data->list;
4909 temp_ptr = (char *)temp_fea;
4910 while(name_len > 0) {
4911 __u16 value_len;
4912 name_len -= 4;
4913 temp_ptr += 4;
4914 rc += temp_fea->name_len;
4915 /* account for prefix user. and trailing null */
4916 rc = rc + 5 + 1;
4917 if(rc<(int)buf_size) {
4918 memcpy(EAData,"user.",5);
4919 EAData+=5;
4920 memcpy(EAData,temp_ptr,temp_fea->name_len);
4921 EAData+=temp_fea->name_len;
4922 /* null terminate name */
4923 *EAData = 0;
4924 EAData = EAData + 1;
4925 } else if(buf_size == 0) {
4926 /* skip copy - calc size only */
4927 } else {
4928 /* stop before overrun buffer */
4929 rc = -ERANGE;
4930 break;
4931 }
4932 name_len -= temp_fea->name_len;
4933 temp_ptr += temp_fea->name_len;
4934 /* account for trailing null */
4935 name_len--;
4936 temp_ptr++;
4937 value_len = le16_to_cpu(temp_fea->value_len);
4938 name_len -= value_len;
4939 temp_ptr += value_len;
4940 /* BB check that temp_ptr is still within smb BB*/
4941 /* no trailing null to account for in value len */
4942 /* go on to next EA */
4943 temp_fea = (struct fea *)temp_ptr;
4944 }
4945 }
4946 }
4947 }
4948 if (pSMB)
4949 cifs_buf_release(pSMB);
4950 if (rc == -EAGAIN)
4951 goto QAllEAsRetry;
4952
4953 return (ssize_t)rc;
4954}
4955
4956ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4957 const unsigned char * searchName,const unsigned char * ea_name,
4958 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004959 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960{
4961 TRANSACTION2_QPI_REQ *pSMB = NULL;
4962 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4963 int rc = 0;
4964 int bytes_returned;
4965 int name_len;
4966 struct fea * temp_fea;
4967 char * temp_ptr;
4968 __u16 params, byte_count;
4969
4970 cFYI(1, ("In Query EA path %s", searchName));
4971QEARetry:
4972 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4973 (void **) &pSMBr);
4974 if (rc)
4975 return rc;
4976
4977 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4978 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004979 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004980 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 name_len++; /* trailing null */
4982 name_len *= 2;
4983 } else { /* BB improve the check for buffer overruns BB */
4984 name_len = strnlen(searchName, PATH_MAX);
4985 name_len++; /* trailing null */
4986 strncpy(pSMB->FileName, searchName, name_len);
4987 }
4988
4989 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4990 pSMB->TotalDataCount = 0;
4991 pSMB->MaxParameterCount = cpu_to_le16(2);
4992 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4993 pSMB->MaxSetupCount = 0;
4994 pSMB->Reserved = 0;
4995 pSMB->Flags = 0;
4996 pSMB->Timeout = 0;
4997 pSMB->Reserved2 = 0;
4998 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4999 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5000 pSMB->DataCount = 0;
5001 pSMB->DataOffset = 0;
5002 pSMB->SetupCount = 1;
5003 pSMB->Reserved3 = 0;
5004 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5005 byte_count = params + 1 /* pad */ ;
5006 pSMB->TotalParameterCount = cpu_to_le16(params);
5007 pSMB->ParameterCount = pSMB->TotalParameterCount;
5008 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5009 pSMB->Reserved4 = 0;
5010 pSMB->hdr.smb_buf_length += byte_count;
5011 pSMB->ByteCount = cpu_to_le16(byte_count);
5012
5013 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5014 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5015 if (rc) {
5016 cFYI(1, ("Send error in Query EA = %d", rc));
5017 } else { /* decode response */
5018 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5019
5020 /* BB also check enough total bytes returned */
5021 /* BB we need to improve the validity checking
5022 of these trans2 responses */
5023 if (rc || (pSMBr->ByteCount < 4))
5024 rc = -EIO; /* bad smb */
5025 /* else if (pFindData){
5026 memcpy((char *) pFindData,
5027 (char *) &pSMBr->hdr.Protocol +
5028 data_offset, kl);
5029 }*/ else {
5030 /* check that length of list is not more than bcc */
5031 /* check that each entry does not go beyond length
5032 of list */
5033 /* check that each element of each entry does not
5034 go beyond end of list */
5035 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5036 struct fealist * ea_response_data;
5037 rc = -ENODATA;
5038 /* validate_trans2_offsets() */
5039 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5040 ea_response_data = (struct fealist *)
5041 (((char *) &pSMBr->hdr.Protocol) +
5042 data_offset);
5043 name_len = le32_to_cpu(ea_response_data->list_len);
5044 cFYI(1,("ea length %d", name_len));
5045 if(name_len <= 8) {
5046 /* returned EA size zeroed at top of function */
5047 cFYI(1,("empty EA list returned from server"));
5048 } else {
5049 /* account for ea list len */
5050 name_len -= 4;
5051 temp_fea = ea_response_data->list;
5052 temp_ptr = (char *)temp_fea;
5053 /* loop through checking if we have a matching
5054 name and then return the associated value */
5055 while(name_len > 0) {
5056 __u16 value_len;
5057 name_len -= 4;
5058 temp_ptr += 4;
5059 value_len = le16_to_cpu(temp_fea->value_len);
5060 /* BB validate that value_len falls within SMB,
5061 even though maximum for name_len is 255 */
5062 if(memcmp(temp_fea->name,ea_name,
5063 temp_fea->name_len) == 0) {
5064 /* found a match */
5065 rc = value_len;
5066 /* account for prefix user. and trailing null */
5067 if(rc<=(int)buf_size) {
5068 memcpy(ea_value,
5069 temp_fea->name+temp_fea->name_len+1,
5070 rc);
5071 /* ea values, unlike ea names,
5072 are not null terminated */
5073 } else if(buf_size == 0) {
5074 /* skip copy - calc size only */
5075 } else {
5076 /* stop before overrun buffer */
5077 rc = -ERANGE;
5078 }
5079 break;
5080 }
5081 name_len -= temp_fea->name_len;
5082 temp_ptr += temp_fea->name_len;
5083 /* account for trailing null */
5084 name_len--;
5085 temp_ptr++;
5086 name_len -= value_len;
5087 temp_ptr += value_len;
5088 /* no trailing null to account for in value len */
5089 /* go on to next EA */
5090 temp_fea = (struct fea *)temp_ptr;
5091 }
5092 }
5093 }
5094 }
5095 if (pSMB)
5096 cifs_buf_release(pSMB);
5097 if (rc == -EAGAIN)
5098 goto QEARetry;
5099
5100 return (ssize_t)rc;
5101}
5102
5103int
5104CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5105 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005106 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5107 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108{
5109 struct smb_com_transaction2_spi_req *pSMB = NULL;
5110 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5111 struct fealist *parm_data;
5112 int name_len;
5113 int rc = 0;
5114 int bytes_returned = 0;
5115 __u16 params, param_offset, byte_count, offset, count;
5116
5117 cFYI(1, ("In SetEA"));
5118SetEARetry:
5119 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5120 (void **) &pSMBr);
5121 if (rc)
5122 return rc;
5123
5124 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5125 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005126 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005127 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 name_len++; /* trailing null */
5129 name_len *= 2;
5130 } else { /* BB improve the check for buffer overruns BB */
5131 name_len = strnlen(fileName, PATH_MAX);
5132 name_len++; /* trailing null */
5133 strncpy(pSMB->FileName, fileName, name_len);
5134 }
5135
5136 params = 6 + name_len;
5137
5138 /* done calculating parms using name_len of file name,
5139 now use name_len to calculate length of ea name
5140 we are going to create in the inode xattrs */
5141 if(ea_name == NULL)
5142 name_len = 0;
5143 else
5144 name_len = strnlen(ea_name,255);
5145
5146 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5147 pSMB->MaxParameterCount = cpu_to_le16(2);
5148 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5149 pSMB->MaxSetupCount = 0;
5150 pSMB->Reserved = 0;
5151 pSMB->Flags = 0;
5152 pSMB->Timeout = 0;
5153 pSMB->Reserved2 = 0;
5154 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5155 InformationLevel) - 4;
5156 offset = param_offset + params;
5157 pSMB->InformationLevel =
5158 cpu_to_le16(SMB_SET_FILE_EA);
5159
5160 parm_data =
5161 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5162 offset);
5163 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5164 pSMB->DataOffset = cpu_to_le16(offset);
5165 pSMB->SetupCount = 1;
5166 pSMB->Reserved3 = 0;
5167 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5168 byte_count = 3 /* pad */ + params + count;
5169 pSMB->DataCount = cpu_to_le16(count);
5170 parm_data->list_len = cpu_to_le32(count);
5171 parm_data->list[0].EA_flags = 0;
5172 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005173 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 /* EA names are always ASCII */
5175 if(ea_name)
5176 strncpy(parm_data->list[0].name,ea_name,name_len);
5177 parm_data->list[0].name[name_len] = 0;
5178 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5179 /* caller ensures that ea_value_len is less than 64K but
5180 we need to ensure that it fits within the smb */
5181
5182 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5183 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5184 if(ea_value_len)
5185 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5186
5187 pSMB->TotalDataCount = pSMB->DataCount;
5188 pSMB->ParameterCount = cpu_to_le16(params);
5189 pSMB->TotalParameterCount = pSMB->ParameterCount;
5190 pSMB->Reserved4 = 0;
5191 pSMB->hdr.smb_buf_length += byte_count;
5192 pSMB->ByteCount = cpu_to_le16(byte_count);
5193 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5194 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5195 if (rc) {
5196 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5197 }
5198
5199 cifs_buf_release(pSMB);
5200
5201 if (rc == -EAGAIN)
5202 goto SetEARetry;
5203
5204 return rc;
5205}
5206
5207#endif