blob: c03c42ee9eb9e549dea7668c54318cc2ddbf7cb3 [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;
Steve French3a5ff612006-07-14 22:37:11 +00001487 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001488 int bytes_returned = 0;
1489 __u16 params, param_offset, offset, byte_count, count;
1490
1491 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001492
1493 if(pLockData == NULL)
1494 return EINVAL;
1495
Steve French08547b02006-02-28 22:39:25 +00001496 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1497
1498 if (rc)
1499 return rc;
1500
1501 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1502
1503 params = 6;
1504 pSMB->MaxSetupCount = 0;
1505 pSMB->Reserved = 0;
1506 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001507 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);
Steve French3a5ff612006-07-14 22:37:11 +00001532 if(waitFlag) {
1533 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001534 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001535 pSMB->Timeout = cpu_to_le32(-1);
1536 } else
1537 pSMB->Timeout = 0;
1538
Steve French08547b02006-02-28 22:39:25 +00001539 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001540 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001541 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001542
1543 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001544 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001545 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1546 pSMB->Reserved4 = 0;
1547 pSMB->hdr.smb_buf_length += byte_count;
1548 pSMB->ByteCount = cpu_to_le16(byte_count);
1549 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001550 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve French08547b02006-02-28 22:39:25 +00001551 if (rc) {
1552 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001553 } else if (get_flag) {
1554 /* lock structure can be returned on get */
1555 __u16 data_offset;
1556 __u16 data_count;
1557 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001558
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001559 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1560 rc = -EIO; /* bad smb */
1561 goto plk_err_exit;
1562 }
1563 if(pLockData == NULL) {
1564 rc = -EINVAL;
1565 goto plk_err_exit;
1566 }
1567 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1568 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1569 if(data_count < sizeof(struct cifs_posix_lock)) {
1570 rc = -EIO;
1571 goto plk_err_exit;
1572 }
1573 parm_data = (struct cifs_posix_lock *)
1574 ((char *)&pSMBr->hdr.Protocol + data_offset);
1575 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1576 pLockData->fl_type = F_UNLCK;
1577 }
1578
1579plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001580 if (pSMB)
1581 cifs_small_buf_release(pSMB);
1582
1583 /* Note: On -EAGAIN error only caller can retry on handle based calls
1584 since file handle passed in no longer valid */
1585
1586 return rc;
1587}
1588
1589
1590int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1592{
1593 int rc = 0;
1594 CLOSE_REQ *pSMB = NULL;
1595 CLOSE_RSP *pSMBr = NULL;
1596 int bytes_returned;
1597 cFYI(1, ("In CIFSSMBClose"));
1598
1599/* do not retry on dead session on close */
1600 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1601 if(rc == -EAGAIN)
1602 return 0;
1603 if (rc)
1604 return rc;
1605
1606 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1607
1608 pSMB->FileID = (__u16) smb_file_id;
1609 pSMB->LastWriteTime = 0;
1610 pSMB->ByteCount = 0;
1611 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1612 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001613 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 if (rc) {
1615 if(rc!=-EINTR) {
1616 /* EINTR is expected when user ctl-c to kill app */
1617 cERROR(1, ("Send error in Close = %d", rc));
1618 }
1619 }
1620
1621 cifs_small_buf_release(pSMB);
1622
1623 /* Since session is dead, file will be closed on server already */
1624 if(rc == -EAGAIN)
1625 rc = 0;
1626
1627 return rc;
1628}
1629
1630int
1631CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1632 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001633 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634{
1635 int rc = 0;
1636 RENAME_REQ *pSMB = NULL;
1637 RENAME_RSP *pSMBr = NULL;
1638 int bytes_returned;
1639 int name_len, name_len2;
1640 __u16 count;
1641
1642 cFYI(1, ("In CIFSSMBRename"));
1643renameRetry:
1644 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1645 (void **) &pSMBr);
1646 if (rc)
1647 return rc;
1648
1649 pSMB->BufferFormat = 0x04;
1650 pSMB->SearchAttributes =
1651 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1652 ATTR_DIRECTORY);
1653
1654 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1655 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001656 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001657 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 name_len++; /* trailing null */
1659 name_len *= 2;
1660 pSMB->OldFileName[name_len] = 0x04; /* pad */
1661 /* protocol requires ASCII signature byte on Unicode string */
1662 pSMB->OldFileName[name_len + 1] = 0x00;
1663 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001664 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001665 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1667 name_len2 *= 2; /* convert to bytes */
1668 } else { /* BB improve the check for buffer overruns BB */
1669 name_len = strnlen(fromName, PATH_MAX);
1670 name_len++; /* trailing null */
1671 strncpy(pSMB->OldFileName, fromName, name_len);
1672 name_len2 = strnlen(toName, PATH_MAX);
1673 name_len2++; /* trailing null */
1674 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1675 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1676 name_len2++; /* trailing null */
1677 name_len2++; /* signature byte */
1678 }
1679
1680 count = 1 /* 1st signature byte */ + name_len + name_len2;
1681 pSMB->hdr.smb_buf_length += count;
1682 pSMB->ByteCount = cpu_to_le16(count);
1683
1684 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1685 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001686 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 if (rc) {
1688 cFYI(1, ("Send error in rename = %d", rc));
1689 }
1690
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 cifs_buf_release(pSMB);
1692
1693 if (rc == -EAGAIN)
1694 goto renameRetry;
1695
1696 return rc;
1697}
1698
1699int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001700 int netfid, char * target_name,
1701 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702{
1703 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1704 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1705 struct set_file_rename * rename_info;
1706 char *data_offset;
1707 char dummy_string[30];
1708 int rc = 0;
1709 int bytes_returned = 0;
1710 int len_of_str;
1711 __u16 params, param_offset, offset, count, byte_count;
1712
1713 cFYI(1, ("Rename to File by handle"));
1714 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1715 (void **) &pSMBr);
1716 if (rc)
1717 return rc;
1718
1719 params = 6;
1720 pSMB->MaxSetupCount = 0;
1721 pSMB->Reserved = 0;
1722 pSMB->Flags = 0;
1723 pSMB->Timeout = 0;
1724 pSMB->Reserved2 = 0;
1725 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1726 offset = param_offset + params;
1727
1728 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1729 rename_info = (struct set_file_rename *) data_offset;
1730 pSMB->MaxParameterCount = cpu_to_le16(2);
1731 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1732 pSMB->SetupCount = 1;
1733 pSMB->Reserved3 = 0;
1734 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1735 byte_count = 3 /* pad */ + params;
1736 pSMB->ParameterCount = cpu_to_le16(params);
1737 pSMB->TotalParameterCount = pSMB->ParameterCount;
1738 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1739 pSMB->DataOffset = cpu_to_le16(offset);
1740 /* construct random name ".cifs_tmp<inodenum><mid>" */
1741 rename_info->overwrite = cpu_to_le32(1);
1742 rename_info->root_fid = 0;
1743 /* unicode only call */
1744 if(target_name == NULL) {
1745 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001746 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001747 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001749 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001750 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1753 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1754 byte_count += count;
1755 pSMB->DataCount = cpu_to_le16(count);
1756 pSMB->TotalDataCount = pSMB->DataCount;
1757 pSMB->Fid = netfid;
1758 pSMB->InformationLevel =
1759 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1760 pSMB->Reserved4 = 0;
1761 pSMB->hdr.smb_buf_length += byte_count;
1762 pSMB->ByteCount = cpu_to_le16(byte_count);
1763 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1764 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001765 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 if (rc) {
1767 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1768 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001769
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 cifs_buf_release(pSMB);
1771
1772 /* Note: On -EAGAIN error only caller can retry on handle based calls
1773 since file handle passed in no longer valid */
1774
1775 return rc;
1776}
1777
1778int
1779CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1780 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001781 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782{
1783 int rc = 0;
1784 COPY_REQ *pSMB = NULL;
1785 COPY_RSP *pSMBr = NULL;
1786 int bytes_returned;
1787 int name_len, name_len2;
1788 __u16 count;
1789
1790 cFYI(1, ("In CIFSSMBCopy"));
1791copyRetry:
1792 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1793 (void **) &pSMBr);
1794 if (rc)
1795 return rc;
1796
1797 pSMB->BufferFormat = 0x04;
1798 pSMB->Tid2 = target_tid;
1799
1800 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1801
1802 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001803 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001804 fromName, PATH_MAX, nls_codepage,
1805 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 name_len++; /* trailing null */
1807 name_len *= 2;
1808 pSMB->OldFileName[name_len] = 0x04; /* pad */
1809 /* protocol requires ASCII signature byte on Unicode string */
1810 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001811 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001812 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1814 name_len2 *= 2; /* convert to bytes */
1815 } else { /* BB improve the check for buffer overruns BB */
1816 name_len = strnlen(fromName, PATH_MAX);
1817 name_len++; /* trailing null */
1818 strncpy(pSMB->OldFileName, fromName, name_len);
1819 name_len2 = strnlen(toName, PATH_MAX);
1820 name_len2++; /* trailing null */
1821 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1822 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1823 name_len2++; /* trailing null */
1824 name_len2++; /* signature byte */
1825 }
1826
1827 count = 1 /* 1st signature byte */ + name_len + name_len2;
1828 pSMB->hdr.smb_buf_length += count;
1829 pSMB->ByteCount = cpu_to_le16(count);
1830
1831 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1833 if (rc) {
1834 cFYI(1, ("Send error in copy = %d with %d files copied",
1835 rc, le16_to_cpu(pSMBr->CopyCount)));
1836 }
1837 if (pSMB)
1838 cifs_buf_release(pSMB);
1839
1840 if (rc == -EAGAIN)
1841 goto copyRetry;
1842
1843 return rc;
1844}
1845
1846int
1847CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1848 const char *fromName, const char *toName,
1849 const struct nls_table *nls_codepage)
1850{
1851 TRANSACTION2_SPI_REQ *pSMB = NULL;
1852 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1853 char *data_offset;
1854 int name_len;
1855 int name_len_target;
1856 int rc = 0;
1857 int bytes_returned = 0;
1858 __u16 params, param_offset, offset, byte_count;
1859
1860 cFYI(1, ("In Symlink Unix style"));
1861createSymLinkRetry:
1862 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1863 (void **) &pSMBr);
1864 if (rc)
1865 return rc;
1866
1867 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1868 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001869 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 /* find define for this maxpathcomponent */
1871 , nls_codepage);
1872 name_len++; /* trailing null */
1873 name_len *= 2;
1874
1875 } else { /* BB improve the check for buffer overruns BB */
1876 name_len = strnlen(fromName, PATH_MAX);
1877 name_len++; /* trailing null */
1878 strncpy(pSMB->FileName, fromName, name_len);
1879 }
1880 params = 6 + name_len;
1881 pSMB->MaxSetupCount = 0;
1882 pSMB->Reserved = 0;
1883 pSMB->Flags = 0;
1884 pSMB->Timeout = 0;
1885 pSMB->Reserved2 = 0;
1886 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1887 InformationLevel) - 4;
1888 offset = param_offset + params;
1889
1890 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1891 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1892 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001893 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 /* find define for this maxpathcomponent */
1895 , nls_codepage);
1896 name_len_target++; /* trailing null */
1897 name_len_target *= 2;
1898 } else { /* BB improve the check for buffer overruns BB */
1899 name_len_target = strnlen(toName, PATH_MAX);
1900 name_len_target++; /* trailing null */
1901 strncpy(data_offset, toName, name_len_target);
1902 }
1903
1904 pSMB->MaxParameterCount = cpu_to_le16(2);
1905 /* BB find exact max on data count below from sess */
1906 pSMB->MaxDataCount = cpu_to_le16(1000);
1907 pSMB->SetupCount = 1;
1908 pSMB->Reserved3 = 0;
1909 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1910 byte_count = 3 /* pad */ + params + name_len_target;
1911 pSMB->DataCount = cpu_to_le16(name_len_target);
1912 pSMB->ParameterCount = cpu_to_le16(params);
1913 pSMB->TotalDataCount = pSMB->DataCount;
1914 pSMB->TotalParameterCount = pSMB->ParameterCount;
1915 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1916 pSMB->DataOffset = cpu_to_le16(offset);
1917 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1918 pSMB->Reserved4 = 0;
1919 pSMB->hdr.smb_buf_length += byte_count;
1920 pSMB->ByteCount = cpu_to_le16(byte_count);
1921 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1922 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001923 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 if (rc) {
1925 cFYI(1,
1926 ("Send error in SetPathInfo (create symlink) = %d",
1927 rc));
1928 }
1929
1930 if (pSMB)
1931 cifs_buf_release(pSMB);
1932
1933 if (rc == -EAGAIN)
1934 goto createSymLinkRetry;
1935
1936 return rc;
1937}
1938
1939int
1940CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1941 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001942 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
1944 TRANSACTION2_SPI_REQ *pSMB = NULL;
1945 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1946 char *data_offset;
1947 int name_len;
1948 int name_len_target;
1949 int rc = 0;
1950 int bytes_returned = 0;
1951 __u16 params, param_offset, offset, byte_count;
1952
1953 cFYI(1, ("In Create Hard link Unix style"));
1954createHardLinkRetry:
1955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1956 (void **) &pSMBr);
1957 if (rc)
1958 return rc;
1959
1960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001961 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001962 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 name_len++; /* trailing null */
1964 name_len *= 2;
1965
1966 } else { /* BB improve the check for buffer overruns BB */
1967 name_len = strnlen(toName, PATH_MAX);
1968 name_len++; /* trailing null */
1969 strncpy(pSMB->FileName, toName, name_len);
1970 }
1971 params = 6 + name_len;
1972 pSMB->MaxSetupCount = 0;
1973 pSMB->Reserved = 0;
1974 pSMB->Flags = 0;
1975 pSMB->Timeout = 0;
1976 pSMB->Reserved2 = 0;
1977 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1978 InformationLevel) - 4;
1979 offset = param_offset + params;
1980
1981 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1982 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1983 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001984 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001985 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 name_len_target++; /* trailing null */
1987 name_len_target *= 2;
1988 } else { /* BB improve the check for buffer overruns BB */
1989 name_len_target = strnlen(fromName, PATH_MAX);
1990 name_len_target++; /* trailing null */
1991 strncpy(data_offset, fromName, name_len_target);
1992 }
1993
1994 pSMB->MaxParameterCount = cpu_to_le16(2);
1995 /* BB find exact max on data count below from sess*/
1996 pSMB->MaxDataCount = cpu_to_le16(1000);
1997 pSMB->SetupCount = 1;
1998 pSMB->Reserved3 = 0;
1999 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2000 byte_count = 3 /* pad */ + params + name_len_target;
2001 pSMB->ParameterCount = cpu_to_le16(params);
2002 pSMB->TotalParameterCount = pSMB->ParameterCount;
2003 pSMB->DataCount = cpu_to_le16(name_len_target);
2004 pSMB->TotalDataCount = pSMB->DataCount;
2005 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2006 pSMB->DataOffset = cpu_to_le16(offset);
2007 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2008 pSMB->Reserved4 = 0;
2009 pSMB->hdr.smb_buf_length += byte_count;
2010 pSMB->ByteCount = cpu_to_le16(byte_count);
2011 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2012 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002013 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 if (rc) {
2015 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2016 }
2017
2018 cifs_buf_release(pSMB);
2019 if (rc == -EAGAIN)
2020 goto createHardLinkRetry;
2021
2022 return rc;
2023}
2024
2025int
2026CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2027 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002028 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029{
2030 int rc = 0;
2031 NT_RENAME_REQ *pSMB = NULL;
2032 RENAME_RSP *pSMBr = NULL;
2033 int bytes_returned;
2034 int name_len, name_len2;
2035 __u16 count;
2036
2037 cFYI(1, ("In CIFSCreateHardLink"));
2038winCreateHardLinkRetry:
2039
2040 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2041 (void **) &pSMBr);
2042 if (rc)
2043 return rc;
2044
2045 pSMB->SearchAttributes =
2046 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2047 ATTR_DIRECTORY);
2048 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2049 pSMB->ClusterCount = 0;
2050
2051 pSMB->BufferFormat = 0x04;
2052
2053 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2054 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002055 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002056 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 name_len++; /* trailing null */
2058 name_len *= 2;
2059 pSMB->OldFileName[name_len] = 0; /* pad */
2060 pSMB->OldFileName[name_len + 1] = 0x04;
2061 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002062 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002063 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2065 name_len2 *= 2; /* convert to bytes */
2066 } else { /* BB improve the check for buffer overruns BB */
2067 name_len = strnlen(fromName, PATH_MAX);
2068 name_len++; /* trailing null */
2069 strncpy(pSMB->OldFileName, fromName, name_len);
2070 name_len2 = strnlen(toName, PATH_MAX);
2071 name_len2++; /* trailing null */
2072 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2073 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2074 name_len2++; /* trailing null */
2075 name_len2++; /* signature byte */
2076 }
2077
2078 count = 1 /* string type byte */ + name_len + name_len2;
2079 pSMB->hdr.smb_buf_length += count;
2080 pSMB->ByteCount = cpu_to_le16(count);
2081
2082 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002084 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 if (rc) {
2086 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2087 }
2088 cifs_buf_release(pSMB);
2089 if (rc == -EAGAIN)
2090 goto winCreateHardLinkRetry;
2091
2092 return rc;
2093}
2094
2095int
2096CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2097 const unsigned char *searchName,
2098 char *symlinkinfo, const int buflen,
2099 const struct nls_table *nls_codepage)
2100{
2101/* SMB_QUERY_FILE_UNIX_LINK */
2102 TRANSACTION2_QPI_REQ *pSMB = NULL;
2103 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2104 int rc = 0;
2105 int bytes_returned;
2106 int name_len;
2107 __u16 params, byte_count;
2108
2109 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2110
2111querySymLinkRetry:
2112 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2113 (void **) &pSMBr);
2114 if (rc)
2115 return rc;
2116
2117 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2118 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002119 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 /* find define for this maxpathcomponent */
2121 , nls_codepage);
2122 name_len++; /* trailing null */
2123 name_len *= 2;
2124 } else { /* BB improve the check for buffer overruns BB */
2125 name_len = strnlen(searchName, PATH_MAX);
2126 name_len++; /* trailing null */
2127 strncpy(pSMB->FileName, searchName, name_len);
2128 }
2129
2130 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2131 pSMB->TotalDataCount = 0;
2132 pSMB->MaxParameterCount = cpu_to_le16(2);
2133 /* BB find exact max data count below from sess structure BB */
2134 pSMB->MaxDataCount = cpu_to_le16(4000);
2135 pSMB->MaxSetupCount = 0;
2136 pSMB->Reserved = 0;
2137 pSMB->Flags = 0;
2138 pSMB->Timeout = 0;
2139 pSMB->Reserved2 = 0;
2140 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2141 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2142 pSMB->DataCount = 0;
2143 pSMB->DataOffset = 0;
2144 pSMB->SetupCount = 1;
2145 pSMB->Reserved3 = 0;
2146 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2147 byte_count = params + 1 /* pad */ ;
2148 pSMB->TotalParameterCount = cpu_to_le16(params);
2149 pSMB->ParameterCount = pSMB->TotalParameterCount;
2150 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2151 pSMB->Reserved4 = 0;
2152 pSMB->hdr.smb_buf_length += byte_count;
2153 pSMB->ByteCount = cpu_to_le16(byte_count);
2154
2155 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2156 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2157 if (rc) {
2158 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2159 } else {
2160 /* decode response */
2161
2162 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2163 if (rc || (pSMBr->ByteCount < 2))
2164 /* BB also check enough total bytes returned */
2165 rc = -EIO; /* bad smb */
2166 else {
2167 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2168 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2169
2170 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2171 name_len = UniStrnlen((wchar_t *) ((char *)
2172 &pSMBr->hdr.Protocol +data_offset),
2173 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002174 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002176 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 data_offset),
2178 name_len, nls_codepage);
2179 } else {
2180 strncpy(symlinkinfo,
2181 (char *) &pSMBr->hdr.Protocol +
2182 data_offset,
2183 min_t(const int, buflen, count));
2184 }
2185 symlinkinfo[buflen] = 0;
2186 /* just in case so calling code does not go off the end of buffer */
2187 }
2188 }
2189 cifs_buf_release(pSMB);
2190 if (rc == -EAGAIN)
2191 goto querySymLinkRetry;
2192 return rc;
2193}
2194
Steve French0a4b92c2006-01-12 15:44:21 -08002195/* Initialize NT TRANSACT SMB into small smb request buffer.
2196 This assumes that all NT TRANSACTS that we init here have
2197 total parm and data under about 400 bytes (to fit in small cifs
2198 buffer size), which is the case so far, it easily fits. NB:
2199 Setup words themselves and ByteCount
2200 MaxSetupCount (size of returned setup area) and
2201 MaxParameterCount (returned parms size) must be set by caller */
2202static int
2203smb_init_ntransact(const __u16 sub_command, const int setup_count,
2204 const int parm_len, struct cifsTconInfo *tcon,
2205 void ** ret_buf)
2206{
2207 int rc;
2208 __u32 temp_offset;
2209 struct smb_com_ntransact_req * pSMB;
2210
2211 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2212 (void **)&pSMB);
2213 if (rc)
2214 return rc;
2215 *ret_buf = (void *)pSMB;
2216 pSMB->Reserved = 0;
2217 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2218 pSMB->TotalDataCount = 0;
2219 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2220 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2221 pSMB->ParameterCount = pSMB->TotalParameterCount;
2222 pSMB->DataCount = pSMB->TotalDataCount;
2223 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2224 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2225 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2226 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2227 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2228 pSMB->SubCommand = cpu_to_le16(sub_command);
2229 return 0;
2230}
2231
2232static int
2233validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2234 int * pdatalen, int * pparmlen)
2235{
2236 char * end_of_smb;
2237 __u32 data_count, data_offset, parm_count, parm_offset;
2238 struct smb_com_ntransact_rsp * pSMBr;
2239
2240 if(buf == NULL)
2241 return -EINVAL;
2242
2243 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2244
2245 /* ByteCount was converted from little endian in SendReceive */
2246 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2247 (char *)&pSMBr->ByteCount;
2248
2249
2250 data_offset = le32_to_cpu(pSMBr->DataOffset);
2251 data_count = le32_to_cpu(pSMBr->DataCount);
2252 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2253 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2254
2255 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2256 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2257
2258 /* should we also check that parm and data areas do not overlap? */
2259 if(*ppparm > end_of_smb) {
2260 cFYI(1,("parms start after end of smb"));
2261 return -EINVAL;
2262 } else if(parm_count + *ppparm > end_of_smb) {
2263 cFYI(1,("parm end after end of smb"));
2264 return -EINVAL;
2265 } else if(*ppdata > end_of_smb) {
2266 cFYI(1,("data starts after end of smb"));
2267 return -EINVAL;
2268 } else if(data_count + *ppdata > end_of_smb) {
2269 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2270 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2271 return -EINVAL;
2272 } else if(parm_count + data_count > pSMBr->ByteCount) {
2273 cFYI(1,("parm count and data count larger than SMB"));
2274 return -EINVAL;
2275 }
2276 return 0;
2277}
2278
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279int
2280CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2281 const unsigned char *searchName,
2282 char *symlinkinfo, const int buflen,__u16 fid,
2283 const struct nls_table *nls_codepage)
2284{
2285 int rc = 0;
2286 int bytes_returned;
2287 int name_len;
2288 struct smb_com_transaction_ioctl_req * pSMB;
2289 struct smb_com_transaction_ioctl_rsp * pSMBr;
2290
2291 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2292 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2293 (void **) &pSMBr);
2294 if (rc)
2295 return rc;
2296
2297 pSMB->TotalParameterCount = 0 ;
2298 pSMB->TotalDataCount = 0;
2299 pSMB->MaxParameterCount = cpu_to_le32(2);
2300 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002301 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2302 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 pSMB->MaxSetupCount = 4;
2304 pSMB->Reserved = 0;
2305 pSMB->ParameterOffset = 0;
2306 pSMB->DataCount = 0;
2307 pSMB->DataOffset = 0;
2308 pSMB->SetupCount = 4;
2309 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2310 pSMB->ParameterCount = pSMB->TotalParameterCount;
2311 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2312 pSMB->IsFsctl = 1; /* FSCTL */
2313 pSMB->IsRootFlag = 0;
2314 pSMB->Fid = fid; /* file handle always le */
2315 pSMB->ByteCount = 0;
2316
2317 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2318 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2319 if (rc) {
2320 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2321 } else { /* decode response */
2322 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2323 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2324 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2325 /* BB also check enough total bytes returned */
2326 rc = -EIO; /* bad smb */
2327 else {
2328 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002329 char * end_of_smb = 2 /* sizeof byte count */ +
2330 pSMBr->ByteCount +
2331 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332
2333 struct reparse_data * reparse_buf = (struct reparse_data *)
2334 ((char *)&pSMBr->hdr.Protocol + data_offset);
2335 if((char*)reparse_buf >= end_of_smb) {
2336 rc = -EIO;
2337 goto qreparse_out;
2338 }
2339 if((reparse_buf->LinkNamesBuf +
2340 reparse_buf->TargetNameOffset +
2341 reparse_buf->TargetNameLen) >
2342 end_of_smb) {
2343 cFYI(1,("reparse buf extended beyond SMB"));
2344 rc = -EIO;
2345 goto qreparse_out;
2346 }
2347
2348 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2349 name_len = UniStrnlen((wchar_t *)
2350 (reparse_buf->LinkNamesBuf +
2351 reparse_buf->TargetNameOffset),
2352 min(buflen/2, reparse_buf->TargetNameLen / 2));
2353 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002354 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 reparse_buf->TargetNameOffset),
2356 name_len, nls_codepage);
2357 } else { /* ASCII names */
2358 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2359 reparse_buf->TargetNameOffset,
2360 min_t(const int, buflen, reparse_buf->TargetNameLen));
2361 }
2362 } else {
2363 rc = -EIO;
2364 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2365 }
2366 symlinkinfo[buflen] = 0; /* just in case so the caller
2367 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002368 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 }
2370 }
2371qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002372 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
2374 /* Note: On -EAGAIN error only caller can retry on handle based calls
2375 since file handle passed in no longer valid */
2376
2377 return rc;
2378}
2379
2380#ifdef CONFIG_CIFS_POSIX
2381
2382/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2383static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2384{
2385 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002386 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2387 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2388 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2390
2391 return;
2392}
2393
2394/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002395static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2396 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397{
2398 int size = 0;
2399 int i;
2400 __u16 count;
2401 struct cifs_posix_ace * pACE;
2402 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2403 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2404
2405 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2406 return -EOPNOTSUPP;
2407
2408 if(acl_type & ACL_TYPE_ACCESS) {
2409 count = le16_to_cpu(cifs_acl->access_entry_count);
2410 pACE = &cifs_acl->ace_array[0];
2411 size = sizeof(struct cifs_posix_acl);
2412 size += sizeof(struct cifs_posix_ace) * count;
2413 /* check if we would go beyond end of SMB */
2414 if(size_of_data_area < size) {
2415 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2416 return -EINVAL;
2417 }
2418 } else if(acl_type & ACL_TYPE_DEFAULT) {
2419 count = le16_to_cpu(cifs_acl->access_entry_count);
2420 size = sizeof(struct cifs_posix_acl);
2421 size += sizeof(struct cifs_posix_ace) * count;
2422/* skip past access ACEs to get to default ACEs */
2423 pACE = &cifs_acl->ace_array[count];
2424 count = le16_to_cpu(cifs_acl->default_entry_count);
2425 size += sizeof(struct cifs_posix_ace) * count;
2426 /* check if we would go beyond end of SMB */
2427 if(size_of_data_area < size)
2428 return -EINVAL;
2429 } else {
2430 /* illegal type */
2431 return -EINVAL;
2432 }
2433
2434 size = posix_acl_xattr_size(count);
2435 if((buflen == 0) || (local_acl == NULL)) {
2436 /* used to query ACL EA size */
2437 } else if(size > buflen) {
2438 return -ERANGE;
2439 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002440 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 for(i = 0;i < count ;i++) {
2442 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2443 pACE ++;
2444 }
2445 }
2446 return size;
2447}
2448
2449static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2450 const posix_acl_xattr_entry * local_ace)
2451{
2452 __u16 rc = 0; /* 0 = ACL converted ok */
2453
Steve Frenchff7feac2005-11-15 16:45:16 -08002454 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2455 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002457 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 /* Probably no need to le convert -1 on any arch but can not hurt */
2459 cifs_ace->cifs_uid = cpu_to_le64(-1);
2460 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002461 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2463 return rc;
2464}
2465
2466/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2467static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2468 const int acl_type)
2469{
2470 __u16 rc = 0;
2471 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2472 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2473 int count;
2474 int i;
2475
2476 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2477 return 0;
2478
2479 count = posix_acl_xattr_count((size_t)buflen);
2480 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002481 count, buflen, le32_to_cpu(local_acl->a_version)));
2482 if(le32_to_cpu(local_acl->a_version) != 2) {
2483 cFYI(1,("unknown POSIX ACL version %d",
2484 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 return 0;
2486 }
2487 cifs_acl->version = cpu_to_le16(1);
2488 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002489 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002491 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 else {
2493 cFYI(1,("unknown ACL type %d",acl_type));
2494 return 0;
2495 }
2496 for(i=0;i<count;i++) {
2497 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2498 &local_acl->a_entries[i]);
2499 if(rc != 0) {
2500 /* ACE not converted */
2501 break;
2502 }
2503 }
2504 if(rc == 0) {
2505 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2506 rc += sizeof(struct cifs_posix_acl);
2507 /* BB add check to make sure ACL does not overflow SMB */
2508 }
2509 return rc;
2510}
2511
2512int
2513CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2514 const unsigned char *searchName,
2515 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002516 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517{
2518/* SMB_QUERY_POSIX_ACL */
2519 TRANSACTION2_QPI_REQ *pSMB = NULL;
2520 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2521 int rc = 0;
2522 int bytes_returned;
2523 int name_len;
2524 __u16 params, byte_count;
2525
2526 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2527
2528queryAclRetry:
2529 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2530 (void **) &pSMBr);
2531 if (rc)
2532 return rc;
2533
2534 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2535 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002536 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002537 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 name_len++; /* trailing null */
2539 name_len *= 2;
2540 pSMB->FileName[name_len] = 0;
2541 pSMB->FileName[name_len+1] = 0;
2542 } else { /* BB improve the check for buffer overruns BB */
2543 name_len = strnlen(searchName, PATH_MAX);
2544 name_len++; /* trailing null */
2545 strncpy(pSMB->FileName, searchName, name_len);
2546 }
2547
2548 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2549 pSMB->TotalDataCount = 0;
2550 pSMB->MaxParameterCount = cpu_to_le16(2);
2551 /* BB find exact max data count below from sess structure BB */
2552 pSMB->MaxDataCount = cpu_to_le16(4000);
2553 pSMB->MaxSetupCount = 0;
2554 pSMB->Reserved = 0;
2555 pSMB->Flags = 0;
2556 pSMB->Timeout = 0;
2557 pSMB->Reserved2 = 0;
2558 pSMB->ParameterOffset = cpu_to_le16(
2559 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2560 pSMB->DataCount = 0;
2561 pSMB->DataOffset = 0;
2562 pSMB->SetupCount = 1;
2563 pSMB->Reserved3 = 0;
2564 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2565 byte_count = params + 1 /* pad */ ;
2566 pSMB->TotalParameterCount = cpu_to_le16(params);
2567 pSMB->ParameterCount = pSMB->TotalParameterCount;
2568 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2569 pSMB->Reserved4 = 0;
2570 pSMB->hdr.smb_buf_length += byte_count;
2571 pSMB->ByteCount = cpu_to_le16(byte_count);
2572
2573 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2574 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002575 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 if (rc) {
2577 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2578 } else {
2579 /* decode response */
2580
2581 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2582 if (rc || (pSMBr->ByteCount < 2))
2583 /* BB also check enough total bytes returned */
2584 rc = -EIO; /* bad smb */
2585 else {
2586 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2587 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2588 rc = cifs_copy_posix_acl(acl_inf,
2589 (char *)&pSMBr->hdr.Protocol+data_offset,
2590 buflen,acl_type,count);
2591 }
2592 }
2593 cifs_buf_release(pSMB);
2594 if (rc == -EAGAIN)
2595 goto queryAclRetry;
2596 return rc;
2597}
2598
2599int
2600CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2601 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002602 const char *local_acl, const int buflen,
2603 const int acl_type,
2604 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605{
2606 struct smb_com_transaction2_spi_req *pSMB = NULL;
2607 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2608 char *parm_data;
2609 int name_len;
2610 int rc = 0;
2611 int bytes_returned = 0;
2612 __u16 params, byte_count, data_count, param_offset, offset;
2613
2614 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2615setAclRetry:
2616 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2617 (void **) &pSMBr);
2618 if (rc)
2619 return rc;
2620 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2621 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002622 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002623 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 name_len++; /* trailing null */
2625 name_len *= 2;
2626 } else { /* BB improve the check for buffer overruns BB */
2627 name_len = strnlen(fileName, PATH_MAX);
2628 name_len++; /* trailing null */
2629 strncpy(pSMB->FileName, fileName, name_len);
2630 }
2631 params = 6 + name_len;
2632 pSMB->MaxParameterCount = cpu_to_le16(2);
2633 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2634 pSMB->MaxSetupCount = 0;
2635 pSMB->Reserved = 0;
2636 pSMB->Flags = 0;
2637 pSMB->Timeout = 0;
2638 pSMB->Reserved2 = 0;
2639 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2640 InformationLevel) - 4;
2641 offset = param_offset + params;
2642 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2643 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2644
2645 /* convert to on the wire format for POSIX ACL */
2646 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2647
2648 if(data_count == 0) {
2649 rc = -EOPNOTSUPP;
2650 goto setACLerrorExit;
2651 }
2652 pSMB->DataOffset = cpu_to_le16(offset);
2653 pSMB->SetupCount = 1;
2654 pSMB->Reserved3 = 0;
2655 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2656 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2657 byte_count = 3 /* pad */ + params + data_count;
2658 pSMB->DataCount = cpu_to_le16(data_count);
2659 pSMB->TotalDataCount = pSMB->DataCount;
2660 pSMB->ParameterCount = cpu_to_le16(params);
2661 pSMB->TotalParameterCount = pSMB->ParameterCount;
2662 pSMB->Reserved4 = 0;
2663 pSMB->hdr.smb_buf_length += byte_count;
2664 pSMB->ByteCount = cpu_to_le16(byte_count);
2665 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2666 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2667 if (rc) {
2668 cFYI(1, ("Set POSIX ACL returned %d", rc));
2669 }
2670
2671setACLerrorExit:
2672 cifs_buf_release(pSMB);
2673 if (rc == -EAGAIN)
2674 goto setAclRetry;
2675 return rc;
2676}
2677
Steve Frenchf654bac2005-04-28 22:41:04 -07002678/* BB fix tabs in this function FIXME BB */
2679int
2680CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2681 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2682{
2683 int rc = 0;
2684 struct smb_t2_qfi_req *pSMB = NULL;
2685 struct smb_t2_qfi_rsp *pSMBr = NULL;
2686 int bytes_returned;
2687 __u16 params, byte_count;
2688
2689 cFYI(1,("In GetExtAttr"));
2690 if(tcon == NULL)
2691 return -ENODEV;
2692
2693GetExtAttrRetry:
2694 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2695 (void **) &pSMBr);
2696 if (rc)
2697 return rc;
2698
Steve Frenchc67593a2005-04-28 22:41:04 -07002699 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002700 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002701 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002702 /* BB find exact max data count below from sess structure BB */
2703 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2704 pSMB->t2.MaxSetupCount = 0;
2705 pSMB->t2.Reserved = 0;
2706 pSMB->t2.Flags = 0;
2707 pSMB->t2.Timeout = 0;
2708 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002709 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2710 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002711 pSMB->t2.DataCount = 0;
2712 pSMB->t2.DataOffset = 0;
2713 pSMB->t2.SetupCount = 1;
2714 pSMB->t2.Reserved3 = 0;
2715 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002716 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002717 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2718 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2719 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002720 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002721 pSMB->Fid = netfid;
2722 pSMB->hdr.smb_buf_length += byte_count;
2723 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2724
2725 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2726 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2727 if (rc) {
2728 cFYI(1, ("error %d in GetExtAttr", rc));
2729 } else {
2730 /* decode response */
2731 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2732 if (rc || (pSMBr->ByteCount < 2))
2733 /* BB also check enough total bytes returned */
2734 /* If rc should we check for EOPNOSUPP and
2735 disable the srvino flag? or in caller? */
2736 rc = -EIO; /* bad smb */
2737 else {
2738 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2739 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2740 struct file_chattr_info * pfinfo;
2741 /* BB Do we need a cast or hash here ? */
2742 if(count != 16) {
2743 cFYI(1, ("Illegal size ret in GetExtAttr"));
2744 rc = -EIO;
2745 goto GetExtAttrOut;
2746 }
2747 pfinfo = (struct file_chattr_info *)
2748 (data_offset + (char *) &pSMBr->hdr.Protocol);
2749 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2750 *pMask = le64_to_cpu(pfinfo->mask);
2751 }
2752 }
2753GetExtAttrOut:
2754 cifs_buf_release(pSMB);
2755 if (rc == -EAGAIN)
2756 goto GetExtAttrRetry;
2757 return rc;
2758}
2759
2760
2761#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
Steve Frencheeac8042006-01-13 21:34:58 -08002763
2764/* security id for everyone */
2765const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2766/* group users */
2767const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2768
Steve French0a4b92c2006-01-12 15:44:21 -08002769/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002770static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002771{
Steve French0a4b92c2006-01-12 15:44:21 -08002772 return 0;
2773}
2774
2775/* Get Security Descriptor (by handle) from remote server for a file or dir */
2776int
2777CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2778 /* BB fix up return info */ char *acl_inf, const int buflen,
2779 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2780{
2781 int rc = 0;
2782 int buf_type = 0;
2783 QUERY_SEC_DESC_REQ * pSMB;
2784 struct kvec iov[1];
2785
2786 cFYI(1, ("GetCifsACL"));
2787
2788 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2789 8 /* parm len */, tcon, (void **) &pSMB);
2790 if (rc)
2791 return rc;
2792
2793 pSMB->MaxParameterCount = cpu_to_le32(4);
2794 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2795 pSMB->MaxSetupCount = 0;
2796 pSMB->Fid = fid; /* file handle always le */
2797 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2798 CIFS_ACL_DACL);
2799 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2800 pSMB->hdr.smb_buf_length += 11;
2801 iov[0].iov_base = (char *)pSMB;
2802 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2803
2804 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2805 cifs_stats_inc(&tcon->num_acl_get);
2806 if (rc) {
2807 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2808 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002809 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002810 __le32 * parm;
2811 int parm_len;
2812 int data_len;
2813 int acl_len;
2814 struct smb_com_ntransact_rsp * pSMBr;
2815
2816/* validate_nttransact */
2817 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2818 (char **)&psec_desc,
2819 &parm_len, &data_len);
2820
2821 if(rc)
2822 goto qsec_out;
2823 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2824
2825 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2826
2827 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2828 rc = -EIO; /* bad smb */
2829 goto qsec_out;
2830 }
2831
2832/* BB check that data area is minimum length and as big as acl_len */
2833
2834 acl_len = le32_to_cpu(*(__le32 *)parm);
2835 /* BB check if(acl_len > bufsize) */
2836
2837 parse_sec_desc(psec_desc, acl_len);
2838 }
2839qsec_out:
2840 if(buf_type == CIFS_SMALL_BUFFER)
2841 cifs_small_buf_release(iov[0].iov_base);
2842 else if(buf_type == CIFS_LARGE_BUFFER)
2843 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002844/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002845 return rc;
2846}
2847
2848
Steve French6b8edfe2005-08-23 20:26:03 -07002849/* Legacy Query Path Information call for lookup to old servers such
2850 as Win9x/WinME */
2851int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2852 const unsigned char *searchName,
2853 FILE_ALL_INFO * pFinfo,
2854 const struct nls_table *nls_codepage, int remap)
2855{
2856 QUERY_INFORMATION_REQ * pSMB;
2857 QUERY_INFORMATION_RSP * pSMBr;
2858 int rc = 0;
2859 int bytes_returned;
2860 int name_len;
2861
2862 cFYI(1, ("In SMBQPath path %s", searchName));
2863QInfRetry:
2864 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2865 (void **) &pSMBr);
2866 if (rc)
2867 return rc;
2868
2869 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2870 name_len =
2871 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2872 PATH_MAX, nls_codepage, remap);
2873 name_len++; /* trailing null */
2874 name_len *= 2;
2875 } else {
2876 name_len = strnlen(searchName, PATH_MAX);
2877 name_len++; /* trailing null */
2878 strncpy(pSMB->FileName, searchName, name_len);
2879 }
2880 pSMB->BufferFormat = 0x04;
2881 name_len++; /* account for buffer type byte */
2882 pSMB->hdr.smb_buf_length += (__u16) name_len;
2883 pSMB->ByteCount = cpu_to_le16(name_len);
2884
2885 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2886 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2887 if (rc) {
2888 cFYI(1, ("Send error in QueryInfo = %d", rc));
2889 } else if (pFinfo) { /* decode response */
2890 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002891 pFinfo->AllocationSize =
2892 cpu_to_le64(le32_to_cpu(pSMBr->size));
2893 pFinfo->EndOfFile = pFinfo->AllocationSize;
2894 pFinfo->Attributes =
2895 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002896 } else
2897 rc = -EIO; /* bad buffer passed in */
2898
2899 cifs_buf_release(pSMB);
2900
2901 if (rc == -EAGAIN)
2902 goto QInfRetry;
2903
2904 return rc;
2905}
2906
2907
2908
2909
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910int
2911CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2912 const unsigned char *searchName,
2913 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002914 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915{
2916/* level 263 SMB_QUERY_FILE_ALL_INFO */
2917 TRANSACTION2_QPI_REQ *pSMB = NULL;
2918 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2919 int rc = 0;
2920 int bytes_returned;
2921 int name_len;
2922 __u16 params, byte_count;
2923
2924/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2925QPathInfoRetry:
2926 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2927 (void **) &pSMBr);
2928 if (rc)
2929 return rc;
2930
2931 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2932 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002933 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002934 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 name_len++; /* trailing null */
2936 name_len *= 2;
2937 } else { /* BB improve the check for buffer overruns BB */
2938 name_len = strnlen(searchName, PATH_MAX);
2939 name_len++; /* trailing null */
2940 strncpy(pSMB->FileName, searchName, name_len);
2941 }
2942
2943 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2944 pSMB->TotalDataCount = 0;
2945 pSMB->MaxParameterCount = cpu_to_le16(2);
2946 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2947 pSMB->MaxSetupCount = 0;
2948 pSMB->Reserved = 0;
2949 pSMB->Flags = 0;
2950 pSMB->Timeout = 0;
2951 pSMB->Reserved2 = 0;
2952 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2953 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2954 pSMB->DataCount = 0;
2955 pSMB->DataOffset = 0;
2956 pSMB->SetupCount = 1;
2957 pSMB->Reserved3 = 0;
2958 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2959 byte_count = params + 1 /* pad */ ;
2960 pSMB->TotalParameterCount = cpu_to_le16(params);
2961 pSMB->ParameterCount = pSMB->TotalParameterCount;
2962 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2963 pSMB->Reserved4 = 0;
2964 pSMB->hdr.smb_buf_length += byte_count;
2965 pSMB->ByteCount = cpu_to_le16(byte_count);
2966
2967 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2968 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2969 if (rc) {
2970 cFYI(1, ("Send error in QPathInfo = %d", rc));
2971 } else { /* decode response */
2972 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2973
2974 if (rc || (pSMBr->ByteCount < 40))
2975 rc = -EIO; /* bad smb */
2976 else if (pFindData){
2977 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2978 memcpy((char *) pFindData,
2979 (char *) &pSMBr->hdr.Protocol +
2980 data_offset, sizeof (FILE_ALL_INFO));
2981 } else
2982 rc = -ENOMEM;
2983 }
2984 cifs_buf_release(pSMB);
2985 if (rc == -EAGAIN)
2986 goto QPathInfoRetry;
2987
2988 return rc;
2989}
2990
2991int
2992CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2993 const unsigned char *searchName,
2994 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002995 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996{
2997/* SMB_QUERY_FILE_UNIX_BASIC */
2998 TRANSACTION2_QPI_REQ *pSMB = NULL;
2999 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3000 int rc = 0;
3001 int bytes_returned = 0;
3002 int name_len;
3003 __u16 params, byte_count;
3004
3005 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3006UnixQPathInfoRetry:
3007 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3008 (void **) &pSMBr);
3009 if (rc)
3010 return rc;
3011
3012 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3013 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003014 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003015 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 name_len++; /* trailing null */
3017 name_len *= 2;
3018 } else { /* BB improve the check for buffer overruns BB */
3019 name_len = strnlen(searchName, PATH_MAX);
3020 name_len++; /* trailing null */
3021 strncpy(pSMB->FileName, searchName, name_len);
3022 }
3023
3024 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3025 pSMB->TotalDataCount = 0;
3026 pSMB->MaxParameterCount = cpu_to_le16(2);
3027 /* BB find exact max SMB PDU from sess structure BB */
3028 pSMB->MaxDataCount = cpu_to_le16(4000);
3029 pSMB->MaxSetupCount = 0;
3030 pSMB->Reserved = 0;
3031 pSMB->Flags = 0;
3032 pSMB->Timeout = 0;
3033 pSMB->Reserved2 = 0;
3034 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3035 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3036 pSMB->DataCount = 0;
3037 pSMB->DataOffset = 0;
3038 pSMB->SetupCount = 1;
3039 pSMB->Reserved3 = 0;
3040 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3041 byte_count = params + 1 /* pad */ ;
3042 pSMB->TotalParameterCount = cpu_to_le16(params);
3043 pSMB->ParameterCount = pSMB->TotalParameterCount;
3044 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3045 pSMB->Reserved4 = 0;
3046 pSMB->hdr.smb_buf_length += byte_count;
3047 pSMB->ByteCount = cpu_to_le16(byte_count);
3048
3049 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3050 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3051 if (rc) {
3052 cFYI(1, ("Send error in QPathInfo = %d", rc));
3053 } else { /* decode response */
3054 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3055
3056 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3057 rc = -EIO; /* bad smb */
3058 } else {
3059 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3060 memcpy((char *) pFindData,
3061 (char *) &pSMBr->hdr.Protocol +
3062 data_offset,
3063 sizeof (FILE_UNIX_BASIC_INFO));
3064 }
3065 }
3066 cifs_buf_release(pSMB);
3067 if (rc == -EAGAIN)
3068 goto UnixQPathInfoRetry;
3069
3070 return rc;
3071}
3072
3073#if 0 /* function unused at present */
3074int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3075 const char *searchName, FILE_ALL_INFO * findData,
3076 const struct nls_table *nls_codepage)
3077{
3078/* level 257 SMB_ */
3079 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3080 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3081 int rc = 0;
3082 int bytes_returned;
3083 int name_len;
3084 __u16 params, byte_count;
3085
3086 cFYI(1, ("In FindUnique"));
3087findUniqueRetry:
3088 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3089 (void **) &pSMBr);
3090 if (rc)
3091 return rc;
3092
3093 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3094 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003095 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 /* find define for this maxpathcomponent */
3097 , nls_codepage);
3098 name_len++; /* trailing null */
3099 name_len *= 2;
3100 } else { /* BB improve the check for buffer overruns BB */
3101 name_len = strnlen(searchName, PATH_MAX);
3102 name_len++; /* trailing null */
3103 strncpy(pSMB->FileName, searchName, name_len);
3104 }
3105
3106 params = 12 + name_len /* includes null */ ;
3107 pSMB->TotalDataCount = 0; /* no EAs */
3108 pSMB->MaxParameterCount = cpu_to_le16(2);
3109 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3110 pSMB->MaxSetupCount = 0;
3111 pSMB->Reserved = 0;
3112 pSMB->Flags = 0;
3113 pSMB->Timeout = 0;
3114 pSMB->Reserved2 = 0;
3115 pSMB->ParameterOffset = cpu_to_le16(
3116 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3117 pSMB->DataCount = 0;
3118 pSMB->DataOffset = 0;
3119 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3120 pSMB->Reserved3 = 0;
3121 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3122 byte_count = params + 1 /* pad */ ;
3123 pSMB->TotalParameterCount = cpu_to_le16(params);
3124 pSMB->ParameterCount = pSMB->TotalParameterCount;
3125 pSMB->SearchAttributes =
3126 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3127 ATTR_DIRECTORY);
3128 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3129 pSMB->SearchFlags = cpu_to_le16(1);
3130 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3131 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3132 pSMB->hdr.smb_buf_length += byte_count;
3133 pSMB->ByteCount = cpu_to_le16(byte_count);
3134
3135 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3136 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3137
3138 if (rc) {
3139 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3140 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003141 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 /* BB fill in */
3143 }
3144
3145 cifs_buf_release(pSMB);
3146 if (rc == -EAGAIN)
3147 goto findUniqueRetry;
3148
3149 return rc;
3150}
3151#endif /* end unused (temporarily) function */
3152
3153/* xid, tcon, searchName and codepage are input parms, rest are returned */
3154int
3155CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3156 const char *searchName,
3157 const struct nls_table *nls_codepage,
3158 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003159 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160{
3161/* level 257 SMB_ */
3162 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3163 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3164 T2_FFIRST_RSP_PARMS * parms;
3165 int rc = 0;
3166 int bytes_returned = 0;
3167 int name_len;
3168 __u16 params, byte_count;
3169
Steve French737b7582005-04-28 22:41:06 -07003170 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
3172findFirstRetry:
3173 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3174 (void **) &pSMBr);
3175 if (rc)
3176 return rc;
3177
3178 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3179 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003180 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003181 PATH_MAX, nls_codepage, remap);
3182 /* We can not add the asterik earlier in case
3183 it got remapped to 0xF03A as if it were part of the
3184 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003186 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003187 pSMB->FileName[name_len+1] = 0;
3188 pSMB->FileName[name_len+2] = '*';
3189 pSMB->FileName[name_len+3] = 0;
3190 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3192 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003193 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 } else { /* BB add check for overrun of SMB buf BB */
3195 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196/* BB fix here and in unicode clause above ie
3197 if(name_len > buffersize-header)
3198 free buffer exit; BB */
3199 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003200 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003201 pSMB->FileName[name_len+1] = '*';
3202 pSMB->FileName[name_len+2] = 0;
3203 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 }
3205
3206 params = 12 + name_len /* includes null */ ;
3207 pSMB->TotalDataCount = 0; /* no EAs */
3208 pSMB->MaxParameterCount = cpu_to_le16(10);
3209 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3210 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3211 pSMB->MaxSetupCount = 0;
3212 pSMB->Reserved = 0;
3213 pSMB->Flags = 0;
3214 pSMB->Timeout = 0;
3215 pSMB->Reserved2 = 0;
3216 byte_count = params + 1 /* pad */ ;
3217 pSMB->TotalParameterCount = cpu_to_le16(params);
3218 pSMB->ParameterCount = pSMB->TotalParameterCount;
3219 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003220 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3221 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 pSMB->DataCount = 0;
3223 pSMB->DataOffset = 0;
3224 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3225 pSMB->Reserved3 = 0;
3226 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3227 pSMB->SearchAttributes =
3228 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3229 ATTR_DIRECTORY);
3230 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3231 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3232 CIFS_SEARCH_RETURN_RESUME);
3233 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3234
3235 /* BB what should we set StorageType to? Does it matter? BB */
3236 pSMB->SearchStorageType = 0;
3237 pSMB->hdr.smb_buf_length += byte_count;
3238 pSMB->ByteCount = cpu_to_le16(byte_count);
3239
3240 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3241 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003242 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243
Steve French88274812006-03-09 22:21:45 +00003244 if (rc) {/* BB add logic to retry regular search if Unix search
3245 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 /* BB Add code to handle unsupported level rc */
3247 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003248
Steve French88274812006-03-09 22:21:45 +00003249 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250
3251 /* BB eventually could optimize out free and realloc of buf */
3252 /* for this case */
3253 if (rc == -EAGAIN)
3254 goto findFirstRetry;
3255 } else { /* decode response */
3256 /* BB remember to free buffer if error BB */
3257 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3258 if(rc == 0) {
3259 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3260 psrch_inf->unicode = TRUE;
3261 else
3262 psrch_inf->unicode = FALSE;
3263
3264 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003265 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 psrch_inf->srch_entries_start =
3267 (char *) &pSMBr->hdr.Protocol +
3268 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3270 le16_to_cpu(pSMBr->t2.ParameterOffset));
3271
3272 if(parms->EndofSearch)
3273 psrch_inf->endOfSearch = TRUE;
3274 else
3275 psrch_inf->endOfSearch = FALSE;
3276
3277 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003278 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 *pnetfid = parms->SearchHandle;
3281 } else {
3282 cifs_buf_release(pSMB);
3283 }
3284 }
3285
3286 return rc;
3287}
3288
3289int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3290 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3291{
3292 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3293 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3294 T2_FNEXT_RSP_PARMS * parms;
3295 char *response_data;
3296 int rc = 0;
3297 int bytes_returned, name_len;
3298 __u16 params, byte_count;
3299
3300 cFYI(1, ("In FindNext"));
3301
3302 if(psrch_inf->endOfSearch == TRUE)
3303 return -ENOENT;
3304
3305 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3306 (void **) &pSMBr);
3307 if (rc)
3308 return rc;
3309
3310 params = 14; /* includes 2 bytes of null string, converted to LE below */
3311 byte_count = 0;
3312 pSMB->TotalDataCount = 0; /* no EAs */
3313 pSMB->MaxParameterCount = cpu_to_le16(8);
3314 pSMB->MaxDataCount =
3315 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3316 pSMB->MaxSetupCount = 0;
3317 pSMB->Reserved = 0;
3318 pSMB->Flags = 0;
3319 pSMB->Timeout = 0;
3320 pSMB->Reserved2 = 0;
3321 pSMB->ParameterOffset = cpu_to_le16(
3322 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3323 pSMB->DataCount = 0;
3324 pSMB->DataOffset = 0;
3325 pSMB->SetupCount = 1;
3326 pSMB->Reserved3 = 0;
3327 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3328 pSMB->SearchHandle = searchHandle; /* always kept as le */
3329 pSMB->SearchCount =
3330 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3331 /* test for Unix extensions */
3332/* if (tcon->ses->capabilities & CAP_UNIX) {
3333 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3334 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3335 } else {
3336 pSMB->InformationLevel =
3337 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3338 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3339 } */
3340 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3341 pSMB->ResumeKey = psrch_inf->resume_key;
3342 pSMB->SearchFlags =
3343 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3344
3345 name_len = psrch_inf->resume_name_len;
3346 params += name_len;
3347 if(name_len < PATH_MAX) {
3348 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3349 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003350 /* 14 byte parm len above enough for 2 byte null terminator */
3351 pSMB->ResumeFileName[name_len] = 0;
3352 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 } else {
3354 rc = -EINVAL;
3355 goto FNext2_err_exit;
3356 }
3357 byte_count = params + 1 /* pad */ ;
3358 pSMB->TotalParameterCount = cpu_to_le16(params);
3359 pSMB->ParameterCount = pSMB->TotalParameterCount;
3360 pSMB->hdr.smb_buf_length += byte_count;
3361 pSMB->ByteCount = cpu_to_le16(byte_count);
3362
3363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3364 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003365 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 if (rc) {
3367 if (rc == -EBADF) {
3368 psrch_inf->endOfSearch = TRUE;
3369 rc = 0; /* search probably was closed at end of search above */
3370 } else
3371 cFYI(1, ("FindNext returned = %d", rc));
3372 } else { /* decode response */
3373 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3374
3375 if(rc == 0) {
3376 /* BB fixme add lock for file (srch_info) struct here */
3377 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3378 psrch_inf->unicode = TRUE;
3379 else
3380 psrch_inf->unicode = FALSE;
3381 response_data = (char *) &pSMBr->hdr.Protocol +
3382 le16_to_cpu(pSMBr->t2.ParameterOffset);
3383 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3384 response_data = (char *)&pSMBr->hdr.Protocol +
3385 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003386 if(psrch_inf->smallBuf)
3387 cifs_small_buf_release(
3388 psrch_inf->ntwrk_buf_start);
3389 else
3390 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 psrch_inf->srch_entries_start = response_data;
3392 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003393 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 if(parms->EndofSearch)
3395 psrch_inf->endOfSearch = TRUE;
3396 else
3397 psrch_inf->endOfSearch = FALSE;
3398
3399 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3400 psrch_inf->index_of_last_entry +=
3401 psrch_inf->entries_in_buffer;
3402/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3403
3404 /* BB fixme add unlock here */
3405 }
3406
3407 }
3408
3409 /* BB On error, should we leave previous search buf (and count and
3410 last entry fields) intact or free the previous one? */
3411
3412 /* Note: On -EAGAIN error only caller can retry on handle based calls
3413 since file handle passed in no longer valid */
3414FNext2_err_exit:
3415 if (rc != 0)
3416 cifs_buf_release(pSMB);
3417
3418 return rc;
3419}
3420
3421int
3422CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3423{
3424 int rc = 0;
3425 FINDCLOSE_REQ *pSMB = NULL;
3426 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3427 int bytes_returned;
3428
3429 cFYI(1, ("In CIFSSMBFindClose"));
3430 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3431
3432 /* no sense returning error if session restarted
3433 as file handle has been closed */
3434 if(rc == -EAGAIN)
3435 return 0;
3436 if (rc)
3437 return rc;
3438
3439 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3440 pSMB->FileID = searchHandle;
3441 pSMB->ByteCount = 0;
3442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3444 if (rc) {
3445 cERROR(1, ("Send error in FindClose = %d", rc));
3446 }
Steve Frencha4544342005-08-24 13:59:35 -07003447 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 cifs_small_buf_release(pSMB);
3449
3450 /* Since session is dead, search handle closed on server already */
3451 if (rc == -EAGAIN)
3452 rc = 0;
3453
3454 return rc;
3455}
3456
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457int
3458CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3459 const unsigned char *searchName,
3460 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003461 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462{
3463 int rc = 0;
3464 TRANSACTION2_QPI_REQ *pSMB = NULL;
3465 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3466 int name_len, bytes_returned;
3467 __u16 params, byte_count;
3468
3469 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3470 if(tcon == NULL)
3471 return -ENODEV;
3472
3473GetInodeNumberRetry:
3474 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3475 (void **) &pSMBr);
3476 if (rc)
3477 return rc;
3478
3479
3480 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3481 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003482 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003483 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 name_len++; /* trailing null */
3485 name_len *= 2;
3486 } else { /* BB improve the check for buffer overruns BB */
3487 name_len = strnlen(searchName, PATH_MAX);
3488 name_len++; /* trailing null */
3489 strncpy(pSMB->FileName, searchName, name_len);
3490 }
3491
3492 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3493 pSMB->TotalDataCount = 0;
3494 pSMB->MaxParameterCount = cpu_to_le16(2);
3495 /* BB find exact max data count below from sess structure BB */
3496 pSMB->MaxDataCount = cpu_to_le16(4000);
3497 pSMB->MaxSetupCount = 0;
3498 pSMB->Reserved = 0;
3499 pSMB->Flags = 0;
3500 pSMB->Timeout = 0;
3501 pSMB->Reserved2 = 0;
3502 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3503 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3504 pSMB->DataCount = 0;
3505 pSMB->DataOffset = 0;
3506 pSMB->SetupCount = 1;
3507 pSMB->Reserved3 = 0;
3508 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3509 byte_count = params + 1 /* pad */ ;
3510 pSMB->TotalParameterCount = cpu_to_le16(params);
3511 pSMB->ParameterCount = pSMB->TotalParameterCount;
3512 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3513 pSMB->Reserved4 = 0;
3514 pSMB->hdr.smb_buf_length += byte_count;
3515 pSMB->ByteCount = cpu_to_le16(byte_count);
3516
3517 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3518 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3519 if (rc) {
3520 cFYI(1, ("error %d in QueryInternalInfo", rc));
3521 } else {
3522 /* decode response */
3523 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3524 if (rc || (pSMBr->ByteCount < 2))
3525 /* BB also check enough total bytes returned */
3526 /* If rc should we check for EOPNOSUPP and
3527 disable the srvino flag? or in caller? */
3528 rc = -EIO; /* bad smb */
3529 else {
3530 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3531 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3532 struct file_internal_info * pfinfo;
3533 /* BB Do we need a cast or hash here ? */
3534 if(count < 8) {
3535 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3536 rc = -EIO;
3537 goto GetInodeNumOut;
3538 }
3539 pfinfo = (struct file_internal_info *)
3540 (data_offset + (char *) &pSMBr->hdr.Protocol);
3541 *inode_number = pfinfo->UniqueId;
3542 }
3543 }
3544GetInodeNumOut:
3545 cifs_buf_release(pSMB);
3546 if (rc == -EAGAIN)
3547 goto GetInodeNumberRetry;
3548 return rc;
3549}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550
3551int
3552CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3553 const unsigned char *searchName,
3554 unsigned char **targetUNCs,
3555 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003556 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557{
3558/* TRANS2_GET_DFS_REFERRAL */
3559 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3560 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3561 struct dfs_referral_level_3 * referrals = NULL;
3562 int rc = 0;
3563 int bytes_returned;
3564 int name_len;
3565 unsigned int i;
3566 char * temp;
3567 __u16 params, byte_count;
3568 *number_of_UNC_in_array = 0;
3569 *targetUNCs = NULL;
3570
3571 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3572 if (ses == NULL)
3573 return -ENODEV;
3574getDFSRetry:
3575 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3576 (void **) &pSMBr);
3577 if (rc)
3578 return rc;
Steve French1982c342005-08-17 12:38:22 -07003579
3580 /* server pointer checked in called function,
3581 but should never be null here anyway */
3582 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 pSMB->hdr.Tid = ses->ipc_tid;
3584 pSMB->hdr.Uid = ses->Suid;
3585 if (ses->capabilities & CAP_STATUS32) {
3586 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3587 }
3588 if (ses->capabilities & CAP_DFS) {
3589 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3590 }
3591
3592 if (ses->capabilities & CAP_UNICODE) {
3593 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3594 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003595 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003596 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 name_len++; /* trailing null */
3598 name_len *= 2;
3599 } else { /* BB improve the check for buffer overruns BB */
3600 name_len = strnlen(searchName, PATH_MAX);
3601 name_len++; /* trailing null */
3602 strncpy(pSMB->RequestFileName, searchName, name_len);
3603 }
3604
3605 params = 2 /* level */ + name_len /*includes null */ ;
3606 pSMB->TotalDataCount = 0;
3607 pSMB->DataCount = 0;
3608 pSMB->DataOffset = 0;
3609 pSMB->MaxParameterCount = 0;
3610 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3611 pSMB->MaxSetupCount = 0;
3612 pSMB->Reserved = 0;
3613 pSMB->Flags = 0;
3614 pSMB->Timeout = 0;
3615 pSMB->Reserved2 = 0;
3616 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3617 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3618 pSMB->SetupCount = 1;
3619 pSMB->Reserved3 = 0;
3620 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3621 byte_count = params + 3 /* pad */ ;
3622 pSMB->ParameterCount = cpu_to_le16(params);
3623 pSMB->TotalParameterCount = pSMB->ParameterCount;
3624 pSMB->MaxReferralLevel = cpu_to_le16(3);
3625 pSMB->hdr.smb_buf_length += byte_count;
3626 pSMB->ByteCount = cpu_to_le16(byte_count);
3627
3628 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3629 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3630 if (rc) {
3631 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3632 } else { /* decode response */
3633/* BB Add logic to parse referrals here */
3634 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3635
3636 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3637 rc = -EIO; /* bad smb */
3638 else {
3639 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3640 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3641
3642 cFYI(1,
3643 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3644 pSMBr->ByteCount, data_offset));
3645 referrals =
3646 (struct dfs_referral_level_3 *)
3647 (8 /* sizeof start of data block */ +
3648 data_offset +
3649 (char *) &pSMBr->hdr.Protocol);
3650 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",
3651 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)));
3652 /* BB This field is actually two bytes in from start of
3653 data block so we could do safety check that DataBlock
3654 begins at address of pSMBr->NumberOfReferrals */
3655 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3656
3657 /* BB Fix below so can return more than one referral */
3658 if(*number_of_UNC_in_array > 1)
3659 *number_of_UNC_in_array = 1;
3660
3661 /* get the length of the strings describing refs */
3662 name_len = 0;
3663 for(i=0;i<*number_of_UNC_in_array;i++) {
3664 /* make sure that DfsPathOffset not past end */
3665 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3666 if (offset > data_count) {
3667 /* if invalid referral, stop here and do
3668 not try to copy any more */
3669 *number_of_UNC_in_array = i;
3670 break;
3671 }
3672 temp = ((char *)referrals) + offset;
3673
3674 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3675 name_len += UniStrnlen((wchar_t *)temp,data_count);
3676 } else {
3677 name_len += strnlen(temp,data_count);
3678 }
3679 referrals++;
3680 /* BB add check that referral pointer does not fall off end PDU */
3681
3682 }
3683 /* BB add check for name_len bigger than bcc */
3684 *targetUNCs =
3685 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3686 if(*targetUNCs == NULL) {
3687 rc = -ENOMEM;
3688 goto GetDFSRefExit;
3689 }
3690 /* copy the ref strings */
3691 referrals =
3692 (struct dfs_referral_level_3 *)
3693 (8 /* sizeof data hdr */ +
3694 data_offset +
3695 (char *) &pSMBr->hdr.Protocol);
3696
3697 for(i=0;i<*number_of_UNC_in_array;i++) {
3698 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3699 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3700 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003701 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 } else {
3703 strncpy(*targetUNCs,temp,name_len);
3704 }
3705 /* BB update target_uncs pointers */
3706 referrals++;
3707 }
3708 temp = *targetUNCs;
3709 temp[name_len] = 0;
3710 }
3711
3712 }
3713GetDFSRefExit:
3714 if (pSMB)
3715 cifs_buf_release(pSMB);
3716
3717 if (rc == -EAGAIN)
3718 goto getDFSRetry;
3719
3720 return rc;
3721}
3722
Steve French20962432005-09-21 22:05:57 -07003723/* Query File System Info such as free space to old servers such as Win 9x */
3724int
3725SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3726{
3727/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3728 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3729 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3730 FILE_SYSTEM_ALLOC_INFO *response_data;
3731 int rc = 0;
3732 int bytes_returned = 0;
3733 __u16 params, byte_count;
3734
3735 cFYI(1, ("OldQFSInfo"));
3736oldQFSInfoRetry:
3737 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3738 (void **) &pSMBr);
3739 if (rc)
3740 return rc;
3741 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3742 (void **) &pSMBr);
3743 if (rc)
3744 return rc;
3745
3746 params = 2; /* level */
3747 pSMB->TotalDataCount = 0;
3748 pSMB->MaxParameterCount = cpu_to_le16(2);
3749 pSMB->MaxDataCount = cpu_to_le16(1000);
3750 pSMB->MaxSetupCount = 0;
3751 pSMB->Reserved = 0;
3752 pSMB->Flags = 0;
3753 pSMB->Timeout = 0;
3754 pSMB->Reserved2 = 0;
3755 byte_count = params + 1 /* pad */ ;
3756 pSMB->TotalParameterCount = cpu_to_le16(params);
3757 pSMB->ParameterCount = pSMB->TotalParameterCount;
3758 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3759 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3760 pSMB->DataCount = 0;
3761 pSMB->DataOffset = 0;
3762 pSMB->SetupCount = 1;
3763 pSMB->Reserved3 = 0;
3764 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3765 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3766 pSMB->hdr.smb_buf_length += byte_count;
3767 pSMB->ByteCount = cpu_to_le16(byte_count);
3768
3769 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3770 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3771 if (rc) {
3772 cFYI(1, ("Send error in QFSInfo = %d", rc));
3773 } else { /* decode response */
3774 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3775
3776 if (rc || (pSMBr->ByteCount < 18))
3777 rc = -EIO; /* bad smb */
3778 else {
3779 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3780 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3781 pSMBr->ByteCount, data_offset));
3782
3783 response_data =
3784 (FILE_SYSTEM_ALLOC_INFO *)
3785 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3786 FSData->f_bsize =
3787 le16_to_cpu(response_data->BytesPerSector) *
3788 le32_to_cpu(response_data->
3789 SectorsPerAllocationUnit);
3790 FSData->f_blocks =
3791 le32_to_cpu(response_data->TotalAllocationUnits);
3792 FSData->f_bfree = FSData->f_bavail =
3793 le32_to_cpu(response_data->FreeAllocationUnits);
3794 cFYI(1,
3795 ("Blocks: %lld Free: %lld Block size %ld",
3796 (unsigned long long)FSData->f_blocks,
3797 (unsigned long long)FSData->f_bfree,
3798 FSData->f_bsize));
3799 }
3800 }
3801 cifs_buf_release(pSMB);
3802
3803 if (rc == -EAGAIN)
3804 goto oldQFSInfoRetry;
3805
3806 return rc;
3807}
3808
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809int
Steve French737b7582005-04-28 22:41:06 -07003810CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811{
3812/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3813 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3814 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3815 FILE_SYSTEM_INFO *response_data;
3816 int rc = 0;
3817 int bytes_returned = 0;
3818 __u16 params, byte_count;
3819
3820 cFYI(1, ("In QFSInfo"));
3821QFSInfoRetry:
3822 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3823 (void **) &pSMBr);
3824 if (rc)
3825 return rc;
3826
3827 params = 2; /* level */
3828 pSMB->TotalDataCount = 0;
3829 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003830 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 pSMB->MaxSetupCount = 0;
3832 pSMB->Reserved = 0;
3833 pSMB->Flags = 0;
3834 pSMB->Timeout = 0;
3835 pSMB->Reserved2 = 0;
3836 byte_count = params + 1 /* pad */ ;
3837 pSMB->TotalParameterCount = cpu_to_le16(params);
3838 pSMB->ParameterCount = pSMB->TotalParameterCount;
3839 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3840 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3841 pSMB->DataCount = 0;
3842 pSMB->DataOffset = 0;
3843 pSMB->SetupCount = 1;
3844 pSMB->Reserved3 = 0;
3845 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3846 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3847 pSMB->hdr.smb_buf_length += byte_count;
3848 pSMB->ByteCount = cpu_to_le16(byte_count);
3849
3850 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3851 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3852 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003853 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 } else { /* decode response */
3855 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3856
Steve French20962432005-09-21 22:05:57 -07003857 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 rc = -EIO; /* bad smb */
3859 else {
3860 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861
3862 response_data =
3863 (FILE_SYSTEM_INFO
3864 *) (((char *) &pSMBr->hdr.Protocol) +
3865 data_offset);
3866 FSData->f_bsize =
3867 le32_to_cpu(response_data->BytesPerSector) *
3868 le32_to_cpu(response_data->
3869 SectorsPerAllocationUnit);
3870 FSData->f_blocks =
3871 le64_to_cpu(response_data->TotalAllocationUnits);
3872 FSData->f_bfree = FSData->f_bavail =
3873 le64_to_cpu(response_data->FreeAllocationUnits);
3874 cFYI(1,
3875 ("Blocks: %lld Free: %lld Block size %ld",
3876 (unsigned long long)FSData->f_blocks,
3877 (unsigned long long)FSData->f_bfree,
3878 FSData->f_bsize));
3879 }
3880 }
3881 cifs_buf_release(pSMB);
3882
3883 if (rc == -EAGAIN)
3884 goto QFSInfoRetry;
3885
3886 return rc;
3887}
3888
3889int
Steve French737b7582005-04-28 22:41:06 -07003890CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891{
3892/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3893 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3894 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3895 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3896 int rc = 0;
3897 int bytes_returned = 0;
3898 __u16 params, byte_count;
3899
3900 cFYI(1, ("In QFSAttributeInfo"));
3901QFSAttributeRetry:
3902 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3903 (void **) &pSMBr);
3904 if (rc)
3905 return rc;
3906
3907 params = 2; /* level */
3908 pSMB->TotalDataCount = 0;
3909 pSMB->MaxParameterCount = cpu_to_le16(2);
3910 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3911 pSMB->MaxSetupCount = 0;
3912 pSMB->Reserved = 0;
3913 pSMB->Flags = 0;
3914 pSMB->Timeout = 0;
3915 pSMB->Reserved2 = 0;
3916 byte_count = params + 1 /* pad */ ;
3917 pSMB->TotalParameterCount = cpu_to_le16(params);
3918 pSMB->ParameterCount = pSMB->TotalParameterCount;
3919 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3920 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3921 pSMB->DataCount = 0;
3922 pSMB->DataOffset = 0;
3923 pSMB->SetupCount = 1;
3924 pSMB->Reserved3 = 0;
3925 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3926 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3927 pSMB->hdr.smb_buf_length += byte_count;
3928 pSMB->ByteCount = cpu_to_le16(byte_count);
3929
3930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3932 if (rc) {
3933 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3934 } else { /* decode response */
3935 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3936
3937 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3938 rc = -EIO; /* bad smb */
3939 } else {
3940 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3941 response_data =
3942 (FILE_SYSTEM_ATTRIBUTE_INFO
3943 *) (((char *) &pSMBr->hdr.Protocol) +
3944 data_offset);
3945 memcpy(&tcon->fsAttrInfo, response_data,
3946 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3947 }
3948 }
3949 cifs_buf_release(pSMB);
3950
3951 if (rc == -EAGAIN)
3952 goto QFSAttributeRetry;
3953
3954 return rc;
3955}
3956
3957int
Steve French737b7582005-04-28 22:41:06 -07003958CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959{
3960/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3961 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3962 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3963 FILE_SYSTEM_DEVICE_INFO *response_data;
3964 int rc = 0;
3965 int bytes_returned = 0;
3966 __u16 params, byte_count;
3967
3968 cFYI(1, ("In QFSDeviceInfo"));
3969QFSDeviceRetry:
3970 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3971 (void **) &pSMBr);
3972 if (rc)
3973 return rc;
3974
3975 params = 2; /* level */
3976 pSMB->TotalDataCount = 0;
3977 pSMB->MaxParameterCount = cpu_to_le16(2);
3978 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3979 pSMB->MaxSetupCount = 0;
3980 pSMB->Reserved = 0;
3981 pSMB->Flags = 0;
3982 pSMB->Timeout = 0;
3983 pSMB->Reserved2 = 0;
3984 byte_count = params + 1 /* pad */ ;
3985 pSMB->TotalParameterCount = cpu_to_le16(params);
3986 pSMB->ParameterCount = pSMB->TotalParameterCount;
3987 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3988 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3989
3990 pSMB->DataCount = 0;
3991 pSMB->DataOffset = 0;
3992 pSMB->SetupCount = 1;
3993 pSMB->Reserved3 = 0;
3994 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3995 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3996 pSMB->hdr.smb_buf_length += byte_count;
3997 pSMB->ByteCount = cpu_to_le16(byte_count);
3998
3999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4001 if (rc) {
4002 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4003 } else { /* decode response */
4004 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4005
4006 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4007 rc = -EIO; /* bad smb */
4008 else {
4009 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4010 response_data =
Steve French737b7582005-04-28 22:41:06 -07004011 (FILE_SYSTEM_DEVICE_INFO *)
4012 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 data_offset);
4014 memcpy(&tcon->fsDevInfo, response_data,
4015 sizeof (FILE_SYSTEM_DEVICE_INFO));
4016 }
4017 }
4018 cifs_buf_release(pSMB);
4019
4020 if (rc == -EAGAIN)
4021 goto QFSDeviceRetry;
4022
4023 return rc;
4024}
4025
4026int
Steve French737b7582005-04-28 22:41:06 -07004027CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028{
4029/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4030 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4031 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4032 FILE_SYSTEM_UNIX_INFO *response_data;
4033 int rc = 0;
4034 int bytes_returned = 0;
4035 __u16 params, byte_count;
4036
4037 cFYI(1, ("In QFSUnixInfo"));
4038QFSUnixRetry:
4039 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4040 (void **) &pSMBr);
4041 if (rc)
4042 return rc;
4043
4044 params = 2; /* level */
4045 pSMB->TotalDataCount = 0;
4046 pSMB->DataCount = 0;
4047 pSMB->DataOffset = 0;
4048 pSMB->MaxParameterCount = cpu_to_le16(2);
4049 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4050 pSMB->MaxSetupCount = 0;
4051 pSMB->Reserved = 0;
4052 pSMB->Flags = 0;
4053 pSMB->Timeout = 0;
4054 pSMB->Reserved2 = 0;
4055 byte_count = params + 1 /* pad */ ;
4056 pSMB->ParameterCount = cpu_to_le16(params);
4057 pSMB->TotalParameterCount = pSMB->ParameterCount;
4058 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4059 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4060 pSMB->SetupCount = 1;
4061 pSMB->Reserved3 = 0;
4062 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4063 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4064 pSMB->hdr.smb_buf_length += byte_count;
4065 pSMB->ByteCount = cpu_to_le16(byte_count);
4066
4067 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4068 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4069 if (rc) {
4070 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4071 } else { /* decode response */
4072 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4073
4074 if (rc || (pSMBr->ByteCount < 13)) {
4075 rc = -EIO; /* bad smb */
4076 } else {
4077 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4078 response_data =
4079 (FILE_SYSTEM_UNIX_INFO
4080 *) (((char *) &pSMBr->hdr.Protocol) +
4081 data_offset);
4082 memcpy(&tcon->fsUnixInfo, response_data,
4083 sizeof (FILE_SYSTEM_UNIX_INFO));
4084 }
4085 }
4086 cifs_buf_release(pSMB);
4087
4088 if (rc == -EAGAIN)
4089 goto QFSUnixRetry;
4090
4091
4092 return rc;
4093}
4094
Jeremy Allisonac670552005-06-22 17:26:35 -07004095int
Steve French45abc6e2005-06-23 13:42:03 -05004096CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004097{
4098/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4099 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4100 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4101 int rc = 0;
4102 int bytes_returned = 0;
4103 __u16 params, param_offset, offset, byte_count;
4104
4105 cFYI(1, ("In SETFSUnixInfo"));
4106SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004107 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004108 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4109 (void **) &pSMBr);
4110 if (rc)
4111 return rc;
4112
4113 params = 4; /* 2 bytes zero followed by info level. */
4114 pSMB->MaxSetupCount = 0;
4115 pSMB->Reserved = 0;
4116 pSMB->Flags = 0;
4117 pSMB->Timeout = 0;
4118 pSMB->Reserved2 = 0;
4119 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4120 offset = param_offset + params;
4121
4122 pSMB->MaxParameterCount = cpu_to_le16(4);
4123 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4124 pSMB->SetupCount = 1;
4125 pSMB->Reserved3 = 0;
4126 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4127 byte_count = 1 /* pad */ + params + 12;
4128
4129 pSMB->DataCount = cpu_to_le16(12);
4130 pSMB->ParameterCount = cpu_to_le16(params);
4131 pSMB->TotalDataCount = pSMB->DataCount;
4132 pSMB->TotalParameterCount = pSMB->ParameterCount;
4133 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4134 pSMB->DataOffset = cpu_to_le16(offset);
4135
4136 /* Params. */
4137 pSMB->FileNum = 0;
4138 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4139
4140 /* Data. */
4141 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4142 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4143 pSMB->ClientUnixCap = cpu_to_le64(cap);
4144
4145 pSMB->hdr.smb_buf_length += byte_count;
4146 pSMB->ByteCount = cpu_to_le16(byte_count);
4147
4148 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4149 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4150 if (rc) {
4151 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4152 } else { /* decode response */
4153 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4154 if (rc) {
4155 rc = -EIO; /* bad smb */
4156 }
4157 }
4158 cifs_buf_release(pSMB);
4159
4160 if (rc == -EAGAIN)
4161 goto SETFSUnixRetry;
4162
4163 return rc;
4164}
4165
4166
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167
4168int
4169CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004170 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171{
4172/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4173 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4174 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4175 FILE_SYSTEM_POSIX_INFO *response_data;
4176 int rc = 0;
4177 int bytes_returned = 0;
4178 __u16 params, byte_count;
4179
4180 cFYI(1, ("In QFSPosixInfo"));
4181QFSPosixRetry:
4182 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4183 (void **) &pSMBr);
4184 if (rc)
4185 return rc;
4186
4187 params = 2; /* level */
4188 pSMB->TotalDataCount = 0;
4189 pSMB->DataCount = 0;
4190 pSMB->DataOffset = 0;
4191 pSMB->MaxParameterCount = cpu_to_le16(2);
4192 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4193 pSMB->MaxSetupCount = 0;
4194 pSMB->Reserved = 0;
4195 pSMB->Flags = 0;
4196 pSMB->Timeout = 0;
4197 pSMB->Reserved2 = 0;
4198 byte_count = params + 1 /* pad */ ;
4199 pSMB->ParameterCount = cpu_to_le16(params);
4200 pSMB->TotalParameterCount = pSMB->ParameterCount;
4201 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4202 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4203 pSMB->SetupCount = 1;
4204 pSMB->Reserved3 = 0;
4205 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4206 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4207 pSMB->hdr.smb_buf_length += byte_count;
4208 pSMB->ByteCount = cpu_to_le16(byte_count);
4209
4210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4212 if (rc) {
4213 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4214 } else { /* decode response */
4215 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4216
4217 if (rc || (pSMBr->ByteCount < 13)) {
4218 rc = -EIO; /* bad smb */
4219 } else {
4220 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4221 response_data =
4222 (FILE_SYSTEM_POSIX_INFO
4223 *) (((char *) &pSMBr->hdr.Protocol) +
4224 data_offset);
4225 FSData->f_bsize =
4226 le32_to_cpu(response_data->BlockSize);
4227 FSData->f_blocks =
4228 le64_to_cpu(response_data->TotalBlocks);
4229 FSData->f_bfree =
4230 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004231 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 FSData->f_bavail = FSData->f_bfree;
4233 } else {
4234 FSData->f_bavail =
4235 le64_to_cpu(response_data->UserBlocksAvail);
4236 }
Steve French70ca7342005-09-22 16:32:06 -07004237 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 FSData->f_files =
4239 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004240 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 FSData->f_ffree =
4242 le64_to_cpu(response_data->FreeFileNodes);
4243 }
4244 }
4245 cifs_buf_release(pSMB);
4246
4247 if (rc == -EAGAIN)
4248 goto QFSPosixRetry;
4249
4250 return rc;
4251}
4252
4253
4254/* We can not use write of zero bytes trick to
4255 set file size due to need for large file support. Also note that
4256 this SetPathInfo is preferred to SetFileInfo based method in next
4257 routine which is only needed to work around a sharing violation bug
4258 in Samba which this routine can run into */
4259
4260int
4261CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004262 __u64 size, int SetAllocation,
4263 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264{
4265 struct smb_com_transaction2_spi_req *pSMB = NULL;
4266 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4267 struct file_end_of_file_info *parm_data;
4268 int name_len;
4269 int rc = 0;
4270 int bytes_returned = 0;
4271 __u16 params, byte_count, data_count, param_offset, offset;
4272
4273 cFYI(1, ("In SetEOF"));
4274SetEOFRetry:
4275 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4276 (void **) &pSMBr);
4277 if (rc)
4278 return rc;
4279
4280 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4281 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004282 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004283 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 name_len++; /* trailing null */
4285 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004286 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 name_len = strnlen(fileName, PATH_MAX);
4288 name_len++; /* trailing null */
4289 strncpy(pSMB->FileName, fileName, name_len);
4290 }
4291 params = 6 + name_len;
4292 data_count = sizeof (struct file_end_of_file_info);
4293 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004294 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 pSMB->MaxSetupCount = 0;
4296 pSMB->Reserved = 0;
4297 pSMB->Flags = 0;
4298 pSMB->Timeout = 0;
4299 pSMB->Reserved2 = 0;
4300 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4301 InformationLevel) - 4;
4302 offset = param_offset + params;
4303 if(SetAllocation) {
4304 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4305 pSMB->InformationLevel =
4306 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4307 else
4308 pSMB->InformationLevel =
4309 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4310 } else /* Set File Size */ {
4311 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4312 pSMB->InformationLevel =
4313 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4314 else
4315 pSMB->InformationLevel =
4316 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4317 }
4318
4319 parm_data =
4320 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4321 offset);
4322 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4323 pSMB->DataOffset = cpu_to_le16(offset);
4324 pSMB->SetupCount = 1;
4325 pSMB->Reserved3 = 0;
4326 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4327 byte_count = 3 /* pad */ + params + data_count;
4328 pSMB->DataCount = cpu_to_le16(data_count);
4329 pSMB->TotalDataCount = pSMB->DataCount;
4330 pSMB->ParameterCount = cpu_to_le16(params);
4331 pSMB->TotalParameterCount = pSMB->ParameterCount;
4332 pSMB->Reserved4 = 0;
4333 pSMB->hdr.smb_buf_length += byte_count;
4334 parm_data->FileSize = cpu_to_le64(size);
4335 pSMB->ByteCount = cpu_to_le16(byte_count);
4336 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4337 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4338 if (rc) {
4339 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4340 }
4341
4342 cifs_buf_release(pSMB);
4343
4344 if (rc == -EAGAIN)
4345 goto SetEOFRetry;
4346
4347 return rc;
4348}
4349
4350int
4351CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4352 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4353{
4354 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4355 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4356 char *data_offset;
4357 struct file_end_of_file_info *parm_data;
4358 int rc = 0;
4359 int bytes_returned = 0;
4360 __u16 params, param_offset, offset, byte_count, count;
4361
4362 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4363 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004364 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4365
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 if (rc)
4367 return rc;
4368
Steve Frenchcd634992005-04-28 22:41:10 -07004369 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4370
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4372 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4373
4374 params = 6;
4375 pSMB->MaxSetupCount = 0;
4376 pSMB->Reserved = 0;
4377 pSMB->Flags = 0;
4378 pSMB->Timeout = 0;
4379 pSMB->Reserved2 = 0;
4380 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4381 offset = param_offset + params;
4382
4383 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4384
4385 count = sizeof(struct file_end_of_file_info);
4386 pSMB->MaxParameterCount = cpu_to_le16(2);
4387 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4388 pSMB->SetupCount = 1;
4389 pSMB->Reserved3 = 0;
4390 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4391 byte_count = 3 /* pad */ + params + count;
4392 pSMB->DataCount = cpu_to_le16(count);
4393 pSMB->ParameterCount = cpu_to_le16(params);
4394 pSMB->TotalDataCount = pSMB->DataCount;
4395 pSMB->TotalParameterCount = pSMB->ParameterCount;
4396 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4397 parm_data =
4398 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4399 offset);
4400 pSMB->DataOffset = cpu_to_le16(offset);
4401 parm_data->FileSize = cpu_to_le64(size);
4402 pSMB->Fid = fid;
4403 if(SetAllocation) {
4404 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4405 pSMB->InformationLevel =
4406 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4407 else
4408 pSMB->InformationLevel =
4409 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4410 } else /* Set File Size */ {
4411 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4412 pSMB->InformationLevel =
4413 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4414 else
4415 pSMB->InformationLevel =
4416 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4417 }
4418 pSMB->Reserved4 = 0;
4419 pSMB->hdr.smb_buf_length += byte_count;
4420 pSMB->ByteCount = cpu_to_le16(byte_count);
4421 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4422 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4423 if (rc) {
4424 cFYI(1,
4425 ("Send error in SetFileInfo (SetFileSize) = %d",
4426 rc));
4427 }
4428
4429 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004430 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431
4432 /* Note: On -EAGAIN error only caller can retry on handle based calls
4433 since file handle passed in no longer valid */
4434
4435 return rc;
4436}
4437
4438/* Some legacy servers such as NT4 require that the file times be set on
4439 an open handle, rather than by pathname - this is awkward due to
4440 potential access conflicts on the open, but it is unavoidable for these
4441 old servers since the only other choice is to go from 100 nanosecond DCE
4442 time and resort to the original setpathinfo level which takes the ancient
4443 DOS time format with 2 second granularity */
4444int
4445CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4446 __u16 fid)
4447{
4448 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4449 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4450 char *data_offset;
4451 int rc = 0;
4452 int bytes_returned = 0;
4453 __u16 params, param_offset, offset, byte_count, count;
4454
4455 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004456 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4457
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 if (rc)
4459 return rc;
4460
Steve Frenchcd634992005-04-28 22:41:10 -07004461 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4462
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 /* At this point there is no need to override the current pid
4464 with the pid of the opener, but that could change if we someday
4465 use an existing handle (rather than opening one on the fly) */
4466 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4467 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4468
4469 params = 6;
4470 pSMB->MaxSetupCount = 0;
4471 pSMB->Reserved = 0;
4472 pSMB->Flags = 0;
4473 pSMB->Timeout = 0;
4474 pSMB->Reserved2 = 0;
4475 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4476 offset = param_offset + params;
4477
4478 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4479
4480 count = sizeof (FILE_BASIC_INFO);
4481 pSMB->MaxParameterCount = cpu_to_le16(2);
4482 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4483 pSMB->SetupCount = 1;
4484 pSMB->Reserved3 = 0;
4485 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4486 byte_count = 3 /* pad */ + params + count;
4487 pSMB->DataCount = cpu_to_le16(count);
4488 pSMB->ParameterCount = cpu_to_le16(params);
4489 pSMB->TotalDataCount = pSMB->DataCount;
4490 pSMB->TotalParameterCount = pSMB->ParameterCount;
4491 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4492 pSMB->DataOffset = cpu_to_le16(offset);
4493 pSMB->Fid = fid;
4494 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4495 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4496 else
4497 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4498 pSMB->Reserved4 = 0;
4499 pSMB->hdr.smb_buf_length += byte_count;
4500 pSMB->ByteCount = cpu_to_le16(byte_count);
4501 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4502 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4504 if (rc) {
4505 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4506 }
4507
Steve Frenchcd634992005-04-28 22:41:10 -07004508 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509
4510 /* Note: On -EAGAIN error only caller can retry on handle based calls
4511 since file handle passed in no longer valid */
4512
4513 return rc;
4514}
4515
4516
4517int
4518CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4519 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004520 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521{
4522 TRANSACTION2_SPI_REQ *pSMB = NULL;
4523 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4524 int name_len;
4525 int rc = 0;
4526 int bytes_returned = 0;
4527 char *data_offset;
4528 __u16 params, param_offset, offset, byte_count, count;
4529
4530 cFYI(1, ("In SetTimes"));
4531
4532SetTimesRetry:
4533 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4534 (void **) &pSMBr);
4535 if (rc)
4536 return rc;
4537
4538 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4539 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004540 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004541 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 name_len++; /* trailing null */
4543 name_len *= 2;
4544 } else { /* BB improve the check for buffer overruns BB */
4545 name_len = strnlen(fileName, PATH_MAX);
4546 name_len++; /* trailing null */
4547 strncpy(pSMB->FileName, fileName, name_len);
4548 }
4549
4550 params = 6 + name_len;
4551 count = sizeof (FILE_BASIC_INFO);
4552 pSMB->MaxParameterCount = cpu_to_le16(2);
4553 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4554 pSMB->MaxSetupCount = 0;
4555 pSMB->Reserved = 0;
4556 pSMB->Flags = 0;
4557 pSMB->Timeout = 0;
4558 pSMB->Reserved2 = 0;
4559 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4560 InformationLevel) - 4;
4561 offset = param_offset + params;
4562 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4563 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4564 pSMB->DataOffset = cpu_to_le16(offset);
4565 pSMB->SetupCount = 1;
4566 pSMB->Reserved3 = 0;
4567 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4568 byte_count = 3 /* pad */ + params + count;
4569
4570 pSMB->DataCount = cpu_to_le16(count);
4571 pSMB->ParameterCount = cpu_to_le16(params);
4572 pSMB->TotalDataCount = pSMB->DataCount;
4573 pSMB->TotalParameterCount = pSMB->ParameterCount;
4574 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4575 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4576 else
4577 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4578 pSMB->Reserved4 = 0;
4579 pSMB->hdr.smb_buf_length += byte_count;
4580 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4581 pSMB->ByteCount = cpu_to_le16(byte_count);
4582 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4583 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4584 if (rc) {
4585 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4586 }
4587
4588 cifs_buf_release(pSMB);
4589
4590 if (rc == -EAGAIN)
4591 goto SetTimesRetry;
4592
4593 return rc;
4594}
4595
4596/* Can not be used to set time stamps yet (due to old DOS time format) */
4597/* Can be used to set attributes */
4598#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4599 handling it anyway and NT4 was what we thought it would be needed for
4600 Do not delete it until we prove whether needed for Win9x though */
4601int
4602CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4603 __u16 dos_attrs, const struct nls_table *nls_codepage)
4604{
4605 SETATTR_REQ *pSMB = NULL;
4606 SETATTR_RSP *pSMBr = NULL;
4607 int rc = 0;
4608 int bytes_returned;
4609 int name_len;
4610
4611 cFYI(1, ("In SetAttrLegacy"));
4612
4613SetAttrLgcyRetry:
4614 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4615 (void **) &pSMBr);
4616 if (rc)
4617 return rc;
4618
4619 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4620 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004621 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 PATH_MAX, nls_codepage);
4623 name_len++; /* trailing null */
4624 name_len *= 2;
4625 } else { /* BB improve the check for buffer overruns BB */
4626 name_len = strnlen(fileName, PATH_MAX);
4627 name_len++; /* trailing null */
4628 strncpy(pSMB->fileName, fileName, name_len);
4629 }
4630 pSMB->attr = cpu_to_le16(dos_attrs);
4631 pSMB->BufferFormat = 0x04;
4632 pSMB->hdr.smb_buf_length += name_len + 1;
4633 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4634 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4635 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4636 if (rc) {
4637 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4638 }
4639
4640 cifs_buf_release(pSMB);
4641
4642 if (rc == -EAGAIN)
4643 goto SetAttrLgcyRetry;
4644
4645 return rc;
4646}
4647#endif /* temporarily unneeded SetAttr legacy function */
4648
4649int
4650CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004651 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4652 dev_t device, const struct nls_table *nls_codepage,
4653 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654{
4655 TRANSACTION2_SPI_REQ *pSMB = NULL;
4656 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4657 int name_len;
4658 int rc = 0;
4659 int bytes_returned = 0;
4660 FILE_UNIX_BASIC_INFO *data_offset;
4661 __u16 params, param_offset, offset, count, byte_count;
4662
4663 cFYI(1, ("In SetUID/GID/Mode"));
4664setPermsRetry:
4665 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4666 (void **) &pSMBr);
4667 if (rc)
4668 return rc;
4669
4670 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4671 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004672 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004673 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674 name_len++; /* trailing null */
4675 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004676 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 name_len = strnlen(fileName, PATH_MAX);
4678 name_len++; /* trailing null */
4679 strncpy(pSMB->FileName, fileName, name_len);
4680 }
4681
4682 params = 6 + name_len;
4683 count = sizeof (FILE_UNIX_BASIC_INFO);
4684 pSMB->MaxParameterCount = cpu_to_le16(2);
4685 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4686 pSMB->MaxSetupCount = 0;
4687 pSMB->Reserved = 0;
4688 pSMB->Flags = 0;
4689 pSMB->Timeout = 0;
4690 pSMB->Reserved2 = 0;
4691 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4692 InformationLevel) - 4;
4693 offset = param_offset + params;
4694 data_offset =
4695 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4696 offset);
4697 memset(data_offset, 0, count);
4698 pSMB->DataOffset = cpu_to_le16(offset);
4699 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4700 pSMB->SetupCount = 1;
4701 pSMB->Reserved3 = 0;
4702 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4703 byte_count = 3 /* pad */ + params + count;
4704 pSMB->ParameterCount = cpu_to_le16(params);
4705 pSMB->DataCount = cpu_to_le16(count);
4706 pSMB->TotalParameterCount = pSMB->ParameterCount;
4707 pSMB->TotalDataCount = pSMB->DataCount;
4708 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4709 pSMB->Reserved4 = 0;
4710 pSMB->hdr.smb_buf_length += byte_count;
4711 data_offset->Uid = cpu_to_le64(uid);
4712 data_offset->Gid = cpu_to_le64(gid);
4713 /* better to leave device as zero when it is */
4714 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4715 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4716 data_offset->Permissions = cpu_to_le64(mode);
4717
4718 if(S_ISREG(mode))
4719 data_offset->Type = cpu_to_le32(UNIX_FILE);
4720 else if(S_ISDIR(mode))
4721 data_offset->Type = cpu_to_le32(UNIX_DIR);
4722 else if(S_ISLNK(mode))
4723 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4724 else if(S_ISCHR(mode))
4725 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4726 else if(S_ISBLK(mode))
4727 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4728 else if(S_ISFIFO(mode))
4729 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4730 else if(S_ISSOCK(mode))
4731 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4732
4733
4734 pSMB->ByteCount = cpu_to_le16(byte_count);
4735 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4736 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4737 if (rc) {
4738 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4739 }
4740
4741 if (pSMB)
4742 cifs_buf_release(pSMB);
4743 if (rc == -EAGAIN)
4744 goto setPermsRetry;
4745 return rc;
4746}
4747
4748int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004749 const int notify_subdirs, const __u16 netfid,
4750 __u32 filter, struct file * pfile, int multishot,
4751 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752{
4753 int rc = 0;
4754 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004755 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004756 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 int bytes_returned;
4758
4759 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4760 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4761 (void **) &pSMBr);
4762 if (rc)
4763 return rc;
4764
4765 pSMB->TotalParameterCount = 0 ;
4766 pSMB->TotalDataCount = 0;
4767 pSMB->MaxParameterCount = cpu_to_le32(2);
4768 /* BB find exact data count max from sess structure BB */
4769 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004770/* BB VERIFY verify which is correct for above BB */
4771 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4772 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4773
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774 pSMB->MaxSetupCount = 4;
4775 pSMB->Reserved = 0;
4776 pSMB->ParameterOffset = 0;
4777 pSMB->DataCount = 0;
4778 pSMB->DataOffset = 0;
4779 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4780 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4781 pSMB->ParameterCount = pSMB->TotalParameterCount;
4782 if(notify_subdirs)
4783 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4784 pSMB->Reserved2 = 0;
4785 pSMB->CompletionFilter = cpu_to_le32(filter);
4786 pSMB->Fid = netfid; /* file handle always le */
4787 pSMB->ByteCount = 0;
4788
4789 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4790 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4791 if (rc) {
4792 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004793 } else {
4794 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004795 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004796 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004797 sizeof(struct dir_notify_req),
4798 GFP_KERNEL);
4799 if(dnotify_req) {
4800 dnotify_req->Pid = pSMB->hdr.Pid;
4801 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4802 dnotify_req->Mid = pSMB->hdr.Mid;
4803 dnotify_req->Tid = pSMB->hdr.Tid;
4804 dnotify_req->Uid = pSMB->hdr.Uid;
4805 dnotify_req->netfid = netfid;
4806 dnotify_req->pfile = pfile;
4807 dnotify_req->filter = filter;
4808 dnotify_req->multishot = multishot;
4809 spin_lock(&GlobalMid_Lock);
4810 list_add_tail(&dnotify_req->lhead,
4811 &GlobalDnotifyReqList);
4812 spin_unlock(&GlobalMid_Lock);
4813 } else
4814 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 }
4816 cifs_buf_release(pSMB);
4817 return rc;
4818}
4819#ifdef CONFIG_CIFS_XATTR
4820ssize_t
4821CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4822 const unsigned char *searchName,
4823 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004824 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825{
4826 /* BB assumes one setup word */
4827 TRANSACTION2_QPI_REQ *pSMB = NULL;
4828 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4829 int rc = 0;
4830 int bytes_returned;
4831 int name_len;
4832 struct fea * temp_fea;
4833 char * temp_ptr;
4834 __u16 params, byte_count;
4835
4836 cFYI(1, ("In Query All EAs path %s", searchName));
4837QAllEAsRetry:
4838 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4839 (void **) &pSMBr);
4840 if (rc)
4841 return rc;
4842
4843 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4844 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004845 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004846 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 name_len++; /* trailing null */
4848 name_len *= 2;
4849 } else { /* BB improve the check for buffer overruns BB */
4850 name_len = strnlen(searchName, PATH_MAX);
4851 name_len++; /* trailing null */
4852 strncpy(pSMB->FileName, searchName, name_len);
4853 }
4854
4855 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4856 pSMB->TotalDataCount = 0;
4857 pSMB->MaxParameterCount = cpu_to_le16(2);
4858 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4859 pSMB->MaxSetupCount = 0;
4860 pSMB->Reserved = 0;
4861 pSMB->Flags = 0;
4862 pSMB->Timeout = 0;
4863 pSMB->Reserved2 = 0;
4864 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4865 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4866 pSMB->DataCount = 0;
4867 pSMB->DataOffset = 0;
4868 pSMB->SetupCount = 1;
4869 pSMB->Reserved3 = 0;
4870 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4871 byte_count = params + 1 /* pad */ ;
4872 pSMB->TotalParameterCount = cpu_to_le16(params);
4873 pSMB->ParameterCount = pSMB->TotalParameterCount;
4874 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4875 pSMB->Reserved4 = 0;
4876 pSMB->hdr.smb_buf_length += byte_count;
4877 pSMB->ByteCount = cpu_to_le16(byte_count);
4878
4879 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4880 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4881 if (rc) {
4882 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4883 } else { /* decode response */
4884 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4885
4886 /* BB also check enough total bytes returned */
4887 /* BB we need to improve the validity checking
4888 of these trans2 responses */
4889 if (rc || (pSMBr->ByteCount < 4))
4890 rc = -EIO; /* bad smb */
4891 /* else if (pFindData){
4892 memcpy((char *) pFindData,
4893 (char *) &pSMBr->hdr.Protocol +
4894 data_offset, kl);
4895 }*/ else {
4896 /* check that length of list is not more than bcc */
4897 /* check that each entry does not go beyond length
4898 of list */
4899 /* check that each element of each entry does not
4900 go beyond end of list */
4901 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4902 struct fealist * ea_response_data;
4903 rc = 0;
4904 /* validate_trans2_offsets() */
4905 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4906 ea_response_data = (struct fealist *)
4907 (((char *) &pSMBr->hdr.Protocol) +
4908 data_offset);
4909 name_len = le32_to_cpu(ea_response_data->list_len);
4910 cFYI(1,("ea length %d", name_len));
4911 if(name_len <= 8) {
4912 /* returned EA size zeroed at top of function */
4913 cFYI(1,("empty EA list returned from server"));
4914 } else {
4915 /* account for ea list len */
4916 name_len -= 4;
4917 temp_fea = ea_response_data->list;
4918 temp_ptr = (char *)temp_fea;
4919 while(name_len > 0) {
4920 __u16 value_len;
4921 name_len -= 4;
4922 temp_ptr += 4;
4923 rc += temp_fea->name_len;
4924 /* account for prefix user. and trailing null */
4925 rc = rc + 5 + 1;
4926 if(rc<(int)buf_size) {
4927 memcpy(EAData,"user.",5);
4928 EAData+=5;
4929 memcpy(EAData,temp_ptr,temp_fea->name_len);
4930 EAData+=temp_fea->name_len;
4931 /* null terminate name */
4932 *EAData = 0;
4933 EAData = EAData + 1;
4934 } else if(buf_size == 0) {
4935 /* skip copy - calc size only */
4936 } else {
4937 /* stop before overrun buffer */
4938 rc = -ERANGE;
4939 break;
4940 }
4941 name_len -= temp_fea->name_len;
4942 temp_ptr += temp_fea->name_len;
4943 /* account for trailing null */
4944 name_len--;
4945 temp_ptr++;
4946 value_len = le16_to_cpu(temp_fea->value_len);
4947 name_len -= value_len;
4948 temp_ptr += value_len;
4949 /* BB check that temp_ptr is still within smb BB*/
4950 /* no trailing null to account for in value len */
4951 /* go on to next EA */
4952 temp_fea = (struct fea *)temp_ptr;
4953 }
4954 }
4955 }
4956 }
4957 if (pSMB)
4958 cifs_buf_release(pSMB);
4959 if (rc == -EAGAIN)
4960 goto QAllEAsRetry;
4961
4962 return (ssize_t)rc;
4963}
4964
4965ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4966 const unsigned char * searchName,const unsigned char * ea_name,
4967 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004968 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969{
4970 TRANSACTION2_QPI_REQ *pSMB = NULL;
4971 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4972 int rc = 0;
4973 int bytes_returned;
4974 int name_len;
4975 struct fea * temp_fea;
4976 char * temp_ptr;
4977 __u16 params, byte_count;
4978
4979 cFYI(1, ("In Query EA path %s", searchName));
4980QEARetry:
4981 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4982 (void **) &pSMBr);
4983 if (rc)
4984 return rc;
4985
4986 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4987 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004988 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004989 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 name_len++; /* trailing null */
4991 name_len *= 2;
4992 } else { /* BB improve the check for buffer overruns BB */
4993 name_len = strnlen(searchName, PATH_MAX);
4994 name_len++; /* trailing null */
4995 strncpy(pSMB->FileName, searchName, name_len);
4996 }
4997
4998 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4999 pSMB->TotalDataCount = 0;
5000 pSMB->MaxParameterCount = cpu_to_le16(2);
5001 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5002 pSMB->MaxSetupCount = 0;
5003 pSMB->Reserved = 0;
5004 pSMB->Flags = 0;
5005 pSMB->Timeout = 0;
5006 pSMB->Reserved2 = 0;
5007 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5008 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5009 pSMB->DataCount = 0;
5010 pSMB->DataOffset = 0;
5011 pSMB->SetupCount = 1;
5012 pSMB->Reserved3 = 0;
5013 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5014 byte_count = params + 1 /* pad */ ;
5015 pSMB->TotalParameterCount = cpu_to_le16(params);
5016 pSMB->ParameterCount = pSMB->TotalParameterCount;
5017 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5018 pSMB->Reserved4 = 0;
5019 pSMB->hdr.smb_buf_length += byte_count;
5020 pSMB->ByteCount = cpu_to_le16(byte_count);
5021
5022 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5023 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5024 if (rc) {
5025 cFYI(1, ("Send error in Query EA = %d", rc));
5026 } else { /* decode response */
5027 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5028
5029 /* BB also check enough total bytes returned */
5030 /* BB we need to improve the validity checking
5031 of these trans2 responses */
5032 if (rc || (pSMBr->ByteCount < 4))
5033 rc = -EIO; /* bad smb */
5034 /* else if (pFindData){
5035 memcpy((char *) pFindData,
5036 (char *) &pSMBr->hdr.Protocol +
5037 data_offset, kl);
5038 }*/ else {
5039 /* check that length of list is not more than bcc */
5040 /* check that each entry does not go beyond length
5041 of list */
5042 /* check that each element of each entry does not
5043 go beyond end of list */
5044 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5045 struct fealist * ea_response_data;
5046 rc = -ENODATA;
5047 /* validate_trans2_offsets() */
5048 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5049 ea_response_data = (struct fealist *)
5050 (((char *) &pSMBr->hdr.Protocol) +
5051 data_offset);
5052 name_len = le32_to_cpu(ea_response_data->list_len);
5053 cFYI(1,("ea length %d", name_len));
5054 if(name_len <= 8) {
5055 /* returned EA size zeroed at top of function */
5056 cFYI(1,("empty EA list returned from server"));
5057 } else {
5058 /* account for ea list len */
5059 name_len -= 4;
5060 temp_fea = ea_response_data->list;
5061 temp_ptr = (char *)temp_fea;
5062 /* loop through checking if we have a matching
5063 name and then return the associated value */
5064 while(name_len > 0) {
5065 __u16 value_len;
5066 name_len -= 4;
5067 temp_ptr += 4;
5068 value_len = le16_to_cpu(temp_fea->value_len);
5069 /* BB validate that value_len falls within SMB,
5070 even though maximum for name_len is 255 */
5071 if(memcmp(temp_fea->name,ea_name,
5072 temp_fea->name_len) == 0) {
5073 /* found a match */
5074 rc = value_len;
5075 /* account for prefix user. and trailing null */
5076 if(rc<=(int)buf_size) {
5077 memcpy(ea_value,
5078 temp_fea->name+temp_fea->name_len+1,
5079 rc);
5080 /* ea values, unlike ea names,
5081 are not null terminated */
5082 } else if(buf_size == 0) {
5083 /* skip copy - calc size only */
5084 } else {
5085 /* stop before overrun buffer */
5086 rc = -ERANGE;
5087 }
5088 break;
5089 }
5090 name_len -= temp_fea->name_len;
5091 temp_ptr += temp_fea->name_len;
5092 /* account for trailing null */
5093 name_len--;
5094 temp_ptr++;
5095 name_len -= value_len;
5096 temp_ptr += value_len;
5097 /* no trailing null to account for in value len */
5098 /* go on to next EA */
5099 temp_fea = (struct fea *)temp_ptr;
5100 }
5101 }
5102 }
5103 }
5104 if (pSMB)
5105 cifs_buf_release(pSMB);
5106 if (rc == -EAGAIN)
5107 goto QEARetry;
5108
5109 return (ssize_t)rc;
5110}
5111
5112int
5113CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5114 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005115 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5116 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117{
5118 struct smb_com_transaction2_spi_req *pSMB = NULL;
5119 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5120 struct fealist *parm_data;
5121 int name_len;
5122 int rc = 0;
5123 int bytes_returned = 0;
5124 __u16 params, param_offset, byte_count, offset, count;
5125
5126 cFYI(1, ("In SetEA"));
5127SetEARetry:
5128 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5129 (void **) &pSMBr);
5130 if (rc)
5131 return rc;
5132
5133 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5134 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005135 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005136 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 name_len++; /* trailing null */
5138 name_len *= 2;
5139 } else { /* BB improve the check for buffer overruns BB */
5140 name_len = strnlen(fileName, PATH_MAX);
5141 name_len++; /* trailing null */
5142 strncpy(pSMB->FileName, fileName, name_len);
5143 }
5144
5145 params = 6 + name_len;
5146
5147 /* done calculating parms using name_len of file name,
5148 now use name_len to calculate length of ea name
5149 we are going to create in the inode xattrs */
5150 if(ea_name == NULL)
5151 name_len = 0;
5152 else
5153 name_len = strnlen(ea_name,255);
5154
5155 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5156 pSMB->MaxParameterCount = cpu_to_le16(2);
5157 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5158 pSMB->MaxSetupCount = 0;
5159 pSMB->Reserved = 0;
5160 pSMB->Flags = 0;
5161 pSMB->Timeout = 0;
5162 pSMB->Reserved2 = 0;
5163 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5164 InformationLevel) - 4;
5165 offset = param_offset + params;
5166 pSMB->InformationLevel =
5167 cpu_to_le16(SMB_SET_FILE_EA);
5168
5169 parm_data =
5170 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5171 offset);
5172 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5173 pSMB->DataOffset = cpu_to_le16(offset);
5174 pSMB->SetupCount = 1;
5175 pSMB->Reserved3 = 0;
5176 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5177 byte_count = 3 /* pad */ + params + count;
5178 pSMB->DataCount = cpu_to_le16(count);
5179 parm_data->list_len = cpu_to_le32(count);
5180 parm_data->list[0].EA_flags = 0;
5181 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005182 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 /* EA names are always ASCII */
5184 if(ea_name)
5185 strncpy(parm_data->list[0].name,ea_name,name_len);
5186 parm_data->list[0].name[name_len] = 0;
5187 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5188 /* caller ensures that ea_value_len is less than 64K but
5189 we need to ensure that it fits within the smb */
5190
5191 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5192 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5193 if(ea_value_len)
5194 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5195
5196 pSMB->TotalDataCount = pSMB->DataCount;
5197 pSMB->ParameterCount = cpu_to_le16(params);
5198 pSMB->TotalParameterCount = pSMB->ParameterCount;
5199 pSMB->Reserved4 = 0;
5200 pSMB->hdr.smb_buf_length += byte_count;
5201 pSMB->ByteCount = cpu_to_le16(byte_count);
5202 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5203 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5204 if (rc) {
5205 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5206 }
5207
5208 cifs_buf_release(pSMB);
5209
5210 if (rc == -EAGAIN)
5211 goto SetEARetry;
5212
5213 return rc;
5214}
5215
5216#endif