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