blob: 99718591ea295d0990662f8711f66235a848f6e2 [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)) {
Steve French25ee4a92006-09-30 00:54:23 +0000450 int tmp, adjust;
Steve French254e55e2006-06-04 05:53:15 +0000451 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
452
Steve French750d1152006-06-27 06:28:30 +0000453 if((secFlags & CIFSSEC_MAY_LANMAN) ||
454 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000455 server->secType = LANMAN;
456 else {
457 cERROR(1, ("mount failed weak security disabled"
458 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000459 rc = -EOPNOTSUPP;
460 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000461 }
462 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
463 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
464 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000465 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000466 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
467 /* even though we do not use raw we might as well set this
468 accurately, in case we ever find a need for it */
469 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
470 server->maxRw = 0xFF00;
471 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
472 } else {
473 server->maxRw = 0;/* we do not need to use raw anyway */
474 server->capabilities = CAP_MPX_MODE;
475 }
476 server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
Steve French25ee4a92006-09-30 00:54:23 +0000477 tmp = le16_to_cpu(rsp->ServerTimeZone);
478 if (tmp == (int)0xffff) {
479 /* OS/2 often does not set timezone therefore
480 * we must use server time to calc time zone.
481 * Could deviate slightly from the right zone. Not easy
482 * to adjust, since timezones are not always a multiple
483 * of 60 (sometimes 30 minutes - are there smaller?)
484 */
485 struct timespec ts, utc;
486 utc = CURRENT_TIME;
487 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
488 le16_to_cpu(rsp->SrvTime.Time));
489 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
490 (int)ts.tv_sec, (int)utc.tv_sec,
491 (int)(utc.tv_sec - ts.tv_sec)));
492 tmp = (int)(utc.tv_sec - ts.tv_sec);
493 adjust = tmp < 0 ? -29 : 29;
494 tmp = ((tmp + adjust) / 60) * 60;
495 server->timeZone = tmp;
496 } else {
497 server->timeZone = tmp * 60; /* also in seconds */
498 }
499 cFYI(1,("server->timeZone: %d seconds", server->timeZone));
500
Steve French39798772006-05-31 22:40:51 +0000501
Steve French254e55e2006-06-04 05:53:15 +0000502 /* BB get server time for time conversions and add
503 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000504
Steve French25ee4a92006-09-30 00:54:23 +0000505 if (rsp->EncryptionKeyLength ==
506 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000507 memcpy(server->cryptKey, rsp->EncryptionKey,
508 CIFS_CRYPTO_KEY_SIZE);
509 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
510 rc = -EIO; /* need cryptkey unless plain text */
511 goto neg_err_exit;
512 }
Steve French39798772006-05-31 22:40:51 +0000513
Steve French254e55e2006-06-04 05:53:15 +0000514 cFYI(1,("LANMAN negotiated"));
515 /* we will not end up setting signing flags - as no signing
516 was in LANMAN and server did not return the flags on */
517 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000518#else /* weak security disabled */
Steve French254e55e2006-06-04 05:53:15 +0000519 } else if(pSMBr->hdr.WordCount == 13) {
520 cERROR(1,("mount failed, cifs module not built "
521 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000522 rc = -EOPNOTSUPP;
523#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000524 goto neg_err_exit;
525 } else if(pSMBr->hdr.WordCount != 17) {
526 /* unknown wct */
527 rc = -EOPNOTSUPP;
528 goto neg_err_exit;
529 }
530 /* else wct == 17 NTLM */
531 server->secMode = pSMBr->SecurityMode;
532 if((server->secMode & SECMODE_USER) == 0)
533 cFYI(1,("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000534
Steve French254e55e2006-06-04 05:53:15 +0000535 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000536#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000537 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000538#endif /* CIFS_WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000539 cERROR(1,("Server requests plain text password"
540 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000541
Steve Frenchf40c5622006-06-28 00:13:38 +0000542 if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000543 server->secType = NTLMv2;
Steve Frenchf40c5622006-06-28 00:13:38 +0000544 else if(secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000545 server->secType = NTLM;
Steve Frenchf40c5622006-06-28 00:13:38 +0000546 else if(secFlags & CIFSSEC_MAY_NTLMV2)
547 server->secType = NTLMv2;
548 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000549
Steve French254e55e2006-06-04 05:53:15 +0000550 /* one byte, so no need to convert this or EncryptionKeyLen from
551 little endian */
552 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
553 /* probably no need to store and check maxvcs */
554 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000556 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
557 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
558 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
559 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
560 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
561 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
562 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
563 CIFS_CRYPTO_KEY_SIZE);
564 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
565 && (pSMBr->EncryptionKeyLength == 0)) {
566 /* decode security blob */
567 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
568 rc = -EIO; /* no crypt key only if plain text pwd */
569 goto neg_err_exit;
570 }
571
572 /* BB might be helpful to save off the domain of server here */
573
574 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
575 (server->capabilities & CAP_EXTENDED_SECURITY)) {
576 count = pSMBr->ByteCount;
577 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000579 else if (count == 16) {
580 server->secType = RawNTLMSSP;
581 if (server->socketUseCount.counter > 1) {
582 if (memcmp(server->server_GUID,
583 pSMBr->u.extended_response.
584 GUID, 16) != 0) {
585 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000587 pSMBr->u.extended_response.GUID,
588 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 }
Steve French254e55e2006-06-04 05:53:15 +0000590 } else
591 memcpy(server->server_GUID,
592 pSMBr->u.extended_response.GUID, 16);
593 } else {
594 rc = decode_negTokenInit(pSMBr->u.extended_response.
595 SecurityBlob,
596 count - 16,
597 &server->secType);
598 if(rc == 1) {
599 /* BB Need to fill struct for sessetup here */
600 rc = -EOPNOTSUPP;
601 } else {
602 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 }
Steve French254e55e2006-06-04 05:53:15 +0000605 } else
606 server->capabilities &= ~CAP_EXTENDED_SECURITY;
607
Steve French6344a422006-06-12 04:18:35 +0000608#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000609signing_check:
Steve French6344a422006-06-12 04:18:35 +0000610#endif
Steve French254e55e2006-06-04 05:53:15 +0000611 if(sign_CIFS_PDUs == FALSE) {
612 if(server->secMode & SECMODE_SIGN_REQUIRED)
613 cERROR(1,("Server requires "
614 "/proc/fs/cifs/PacketSigningEnabled to be on"));
615 server->secMode &=
616 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
617 } else if(sign_CIFS_PDUs == 1) {
618 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
619 server->secMode &=
620 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
621 } else if(sign_CIFS_PDUs == 2) {
622 if((server->secMode &
623 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
624 cERROR(1,("signing required but server lacks support"));
625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 }
Steve French39798772006-05-31 22:40:51 +0000627neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700628 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000629
630 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 return rc;
632}
633
634int
635CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
636{
637 struct smb_hdr *smb_buffer;
638 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
639 int rc = 0;
640 int length;
641
642 cFYI(1, ("In tree disconnect"));
643 /*
644 * If last user of the connection and
645 * connection alive - disconnect it
646 * If this is the last connection on the server session disconnect it
647 * (and inside session disconnect we should check if tcp socket needs
648 * to be freed and kernel thread woken up).
649 */
650 if (tcon)
651 down(&tcon->tconSem);
652 else
653 return -EIO;
654
655 atomic_dec(&tcon->useCount);
656 if (atomic_read(&tcon->useCount) > 0) {
657 up(&tcon->tconSem);
658 return -EBUSY;
659 }
660
661 /* No need to return error on this operation if tid invalidated and
662 closed on server already e.g. due to tcp session crashing */
663 if(tcon->tidStatus == CifsNeedReconnect) {
664 up(&tcon->tconSem);
665 return 0;
666 }
667
668 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
669 up(&tcon->tconSem);
670 return -EIO;
671 }
Steve French09d1db52005-04-28 22:41:08 -0700672 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
673 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (rc) {
675 up(&tcon->tconSem);
676 return rc;
677 } else {
678 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
681 &length, 0);
682 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700683 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 if (smb_buffer)
686 cifs_small_buf_release(smb_buffer);
687 up(&tcon->tconSem);
688
689 /* No need to return error on this operation if tid invalidated and
690 closed on server already e.g. due to tcp session crashing */
691 if (rc == -EAGAIN)
692 rc = 0;
693
694 return rc;
695}
696
697int
698CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
699{
700 struct smb_hdr *smb_buffer_response;
701 LOGOFF_ANDX_REQ *pSMB;
702 int rc = 0;
703 int length;
704
705 cFYI(1, ("In SMBLogoff for session disconnect"));
706 if (ses)
707 down(&ses->sesSem);
708 else
709 return -EIO;
710
711 atomic_dec(&ses->inUse);
712 if (atomic_read(&ses->inUse) > 0) {
713 up(&ses->sesSem);
714 return -EBUSY;
715 }
716 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
717 if (rc) {
718 up(&ses->sesSem);
719 return rc;
720 }
721
722 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
723
724 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700725 pSMB->hdr.Mid = GetNextMid(ses->server);
726
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 if(ses->server->secMode &
728 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
729 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
730 }
731
732 pSMB->hdr.Uid = ses->Suid;
733
734 pSMB->AndXCommand = 0xFF;
735 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
736 smb_buffer_response, &length, 0);
737 if (ses->server) {
738 atomic_dec(&ses->server->socketUseCount);
739 if (atomic_read(&ses->server->socketUseCount) == 0) {
740 spin_lock(&GlobalMid_Lock);
741 ses->server->tcpStatus = CifsExiting;
742 spin_unlock(&GlobalMid_Lock);
743 rc = -ESHUTDOWN;
744 }
745 }
Steve Frencha59c6582005-08-17 12:12:19 -0700746 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700747 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
749 /* if session dead then we do not need to do ulogoff,
750 since server closed smb session, no sense reporting
751 error */
752 if (rc == -EAGAIN)
753 rc = 0;
754 return rc;
755}
756
757int
Steve French737b7582005-04-28 22:41:06 -0700758CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
759 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
761 DELETE_FILE_REQ *pSMB = NULL;
762 DELETE_FILE_RSP *pSMBr = NULL;
763 int rc = 0;
764 int bytes_returned;
765 int name_len;
766
767DelFileRetry:
768 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
769 (void **) &pSMBr);
770 if (rc)
771 return rc;
772
773 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
774 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500775 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700776 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 name_len++; /* trailing null */
778 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700779 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 name_len = strnlen(fileName, PATH_MAX);
781 name_len++; /* trailing null */
782 strncpy(pSMB->fileName, fileName, name_len);
783 }
784 pSMB->SearchAttributes =
785 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
786 pSMB->BufferFormat = 0x04;
787 pSMB->hdr.smb_buf_length += name_len + 1;
788 pSMB->ByteCount = cpu_to_le16(name_len + 1);
789 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
790 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700791 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 if (rc) {
793 cFYI(1, ("Error in RMFile = %d", rc));
794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796 cifs_buf_release(pSMB);
797 if (rc == -EAGAIN)
798 goto DelFileRetry;
799
800 return rc;
801}
802
803int
Steve French737b7582005-04-28 22:41:06 -0700804CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
805 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806{
807 DELETE_DIRECTORY_REQ *pSMB = NULL;
808 DELETE_DIRECTORY_RSP *pSMBr = NULL;
809 int rc = 0;
810 int bytes_returned;
811 int name_len;
812
813 cFYI(1, ("In CIFSSMBRmDir"));
814RmDirRetry:
815 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
816 (void **) &pSMBr);
817 if (rc)
818 return rc;
819
820 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700821 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
822 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 name_len++; /* trailing null */
824 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700825 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 name_len = strnlen(dirName, PATH_MAX);
827 name_len++; /* trailing null */
828 strncpy(pSMB->DirName, dirName, name_len);
829 }
830
831 pSMB->BufferFormat = 0x04;
832 pSMB->hdr.smb_buf_length += name_len + 1;
833 pSMB->ByteCount = cpu_to_le16(name_len + 1);
834 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
835 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700836 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 if (rc) {
838 cFYI(1, ("Error in RMDir = %d", rc));
839 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
841 cifs_buf_release(pSMB);
842 if (rc == -EAGAIN)
843 goto RmDirRetry;
844 return rc;
845}
846
847int
848CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700849 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850{
851 int rc = 0;
852 CREATE_DIRECTORY_REQ *pSMB = NULL;
853 CREATE_DIRECTORY_RSP *pSMBr = NULL;
854 int bytes_returned;
855 int name_len;
856
857 cFYI(1, ("In CIFSSMBMkDir"));
858MkDirRetry:
859 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
860 (void **) &pSMBr);
861 if (rc)
862 return rc;
863
864 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500865 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700866 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 name_len++; /* trailing null */
868 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700869 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 name_len = strnlen(name, PATH_MAX);
871 name_len++; /* trailing null */
872 strncpy(pSMB->DirName, name, name_len);
873 }
874
875 pSMB->BufferFormat = 0x04;
876 pSMB->hdr.smb_buf_length += name_len + 1;
877 pSMB->ByteCount = cpu_to_le16(name_len + 1);
878 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
879 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700880 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 if (rc) {
882 cFYI(1, ("Error in Mkdir = %d", rc));
883 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700884
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 cifs_buf_release(pSMB);
886 if (rc == -EAGAIN)
887 goto MkDirRetry;
888 return rc;
889}
890
Steve Frencha9d02ad2005-08-24 23:06:05 -0700891static __u16 convert_disposition(int disposition)
892{
893 __u16 ofun = 0;
894
895 switch (disposition) {
896 case FILE_SUPERSEDE:
897 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
898 break;
899 case FILE_OPEN:
900 ofun = SMBOPEN_OAPPEND;
901 break;
902 case FILE_CREATE:
903 ofun = SMBOPEN_OCREATE;
904 break;
905 case FILE_OPEN_IF:
906 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
907 break;
908 case FILE_OVERWRITE:
909 ofun = SMBOPEN_OTRUNC;
910 break;
911 case FILE_OVERWRITE_IF:
912 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
913 break;
914 default:
915 cFYI(1,("unknown disposition %d",disposition));
916 ofun = SMBOPEN_OAPPEND; /* regular open */
917 }
918 return ofun;
919}
920
921int
922SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
923 const char *fileName, const int openDisposition,
924 const int access_flags, const int create_options, __u16 * netfid,
925 int *pOplock, FILE_ALL_INFO * pfile_info,
926 const struct nls_table *nls_codepage, int remap)
927{
928 int rc = -EACCES;
929 OPENX_REQ *pSMB = NULL;
930 OPENX_RSP *pSMBr = NULL;
931 int bytes_returned;
932 int name_len;
933 __u16 count;
934
935OldOpenRetry:
936 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
937 (void **) &pSMBr);
938 if (rc)
939 return rc;
940
941 pSMB->AndXCommand = 0xFF; /* none */
942
943 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
944 count = 1; /* account for one byte pad to word boundary */
945 name_len =
946 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
947 fileName, PATH_MAX, nls_codepage, remap);
948 name_len++; /* trailing null */
949 name_len *= 2;
950 } else { /* BB improve check for buffer overruns BB */
951 count = 0; /* no pad */
952 name_len = strnlen(fileName, PATH_MAX);
953 name_len++; /* trailing null */
954 strncpy(pSMB->fileName, fileName, name_len);
955 }
956 if (*pOplock & REQ_OPLOCK)
957 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
958 else if (*pOplock & REQ_BATCHOPLOCK) {
959 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
960 }
961 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
962 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
963 /* 0 = read
964 1 = write
965 2 = rw
966 3 = execute
967 */
968 pSMB->Mode = cpu_to_le16(2);
969 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
970 /* set file as system file if special file such
971 as fifo and server expecting SFU style and
972 no Unix extensions */
973
974 if(create_options & CREATE_OPTION_SPECIAL)
975 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
976 else
Steve French3e87d802005-09-18 20:49:21 -0700977 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700978
979 /* if ((omode & S_IWUGO) == 0)
980 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
981 /* Above line causes problems due to vfs splitting create into two
982 pieces - need to set mode after file created not while it is
983 being created */
984
985 /* BB FIXME BB */
986/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
987 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700988
989 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700990 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700991 count += name_len;
992 pSMB->hdr.smb_buf_length += count;
993
994 pSMB->ByteCount = cpu_to_le16(count);
995 /* long_op set to 1 to allow for oplock break timeouts */
996 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
997 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
998 cifs_stats_inc(&tcon->num_opens);
999 if (rc) {
1000 cFYI(1, ("Error in Open = %d", rc));
1001 } else {
1002 /* BB verify if wct == 15 */
1003
1004/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1005
1006 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1007 /* Let caller know file was created so we can set the mode. */
1008 /* Do we care about the CreateAction in any other cases? */
1009 /* BB FIXME BB */
1010/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1011 *pOplock |= CIFS_CREATE_ACTION; */
1012 /* BB FIXME END */
1013
1014 if(pfile_info) {
1015 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1016 pfile_info->LastAccessTime = 0; /* BB fixme */
1017 pfile_info->LastWriteTime = 0; /* BB fixme */
1018 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001019 pfile_info->Attributes =
1020 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001021 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001022 pfile_info->AllocationSize =
1023 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1024 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001025 pfile_info->NumberOfLinks = cpu_to_le32(1);
1026 }
1027 }
1028
1029 cifs_buf_release(pSMB);
1030 if (rc == -EAGAIN)
1031 goto OldOpenRetry;
1032 return rc;
1033}
1034
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035int
1036CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1037 const char *fileName, const int openDisposition,
1038 const int access_flags, const int create_options, __u16 * netfid,
1039 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001040 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041{
1042 int rc = -EACCES;
1043 OPEN_REQ *pSMB = NULL;
1044 OPEN_RSP *pSMBr = NULL;
1045 int bytes_returned;
1046 int name_len;
1047 __u16 count;
1048
1049openRetry:
1050 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1051 (void **) &pSMBr);
1052 if (rc)
1053 return rc;
1054
1055 pSMB->AndXCommand = 0xFF; /* none */
1056
1057 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1058 count = 1; /* account for one byte pad to word boundary */
1059 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001060 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001061 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 name_len++; /* trailing null */
1063 name_len *= 2;
1064 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001065 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 count = 0; /* no pad */
1067 name_len = strnlen(fileName, PATH_MAX);
1068 name_len++; /* trailing null */
1069 pSMB->NameLength = cpu_to_le16(name_len);
1070 strncpy(pSMB->fileName, fileName, name_len);
1071 }
1072 if (*pOplock & REQ_OPLOCK)
1073 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1074 else if (*pOplock & REQ_BATCHOPLOCK) {
1075 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1076 }
1077 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1078 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001079 /* set file as system file if special file such
1080 as fifo and server expecting SFU style and
1081 no Unix extensions */
1082 if(create_options & CREATE_OPTION_SPECIAL)
1083 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1084 else
1085 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 /* XP does not handle ATTR_POSIX_SEMANTICS */
1087 /* but it helps speed up case sensitive checks for other
1088 servers such as Samba */
1089 if (tcon->ses->capabilities & CAP_UNIX)
1090 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1091
1092 /* if ((omode & S_IWUGO) == 0)
1093 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1094 /* Above line causes problems due to vfs splitting create into two
1095 pieces - need to set mode after file created not while it is
1096 being created */
1097 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1098 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001099 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001100 /* BB Expirement with various impersonation levels and verify */
1101 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 pSMB->SecurityFlags =
1103 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1104
1105 count += name_len;
1106 pSMB->hdr.smb_buf_length += count;
1107
1108 pSMB->ByteCount = cpu_to_le16(count);
1109 /* long_op set to 1 to allow for oplock break timeouts */
1110 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1111 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001112 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 if (rc) {
1114 cFYI(1, ("Error in Open = %d", rc));
1115 } else {
Steve French09d1db52005-04-28 22:41:08 -07001116 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1118 /* Let caller know file was created so we can set the mode. */
1119 /* Do we care about the CreateAction in any other cases? */
1120 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1121 *pOplock |= CIFS_CREATE_ACTION;
1122 if(pfile_info) {
1123 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1124 36 /* CreationTime to Attributes */);
1125 /* the file_info buf is endian converted by caller */
1126 pfile_info->AllocationSize = pSMBr->AllocationSize;
1127 pfile_info->EndOfFile = pSMBr->EndOfFile;
1128 pfile_info->NumberOfLinks = cpu_to_le32(1);
1129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001131
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 cifs_buf_release(pSMB);
1133 if (rc == -EAGAIN)
1134 goto openRetry;
1135 return rc;
1136}
1137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138int
1139CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001140 const int netfid, const unsigned int count,
1141 const __u64 lseek, unsigned int *nbytes, char **buf,
1142 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
1144 int rc = -EACCES;
1145 READ_REQ *pSMB = NULL;
1146 READ_RSP *pSMBr = NULL;
1147 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001148 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001149 int resp_buf_type = 0;
1150 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
1152 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001153 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1154 wct = 12;
1155 else
1156 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
1158 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001159 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (rc)
1161 return rc;
1162
1163 /* tcon and ses pointer are checked in smb_init */
1164 if (tcon->ses->server == NULL)
1165 return -ECONNABORTED;
1166
Steve Frenchec637e32005-12-12 20:53:18 -08001167 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 pSMB->Fid = netfid;
1169 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001170 if(wct == 12)
1171 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001172 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1173 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 pSMB->Remaining = 0;
1176 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1177 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001178 if(wct == 12)
1179 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1180 else {
1181 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001182 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001183 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001184 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001185 }
Steve Frenchec637e32005-12-12 20:53:18 -08001186
1187 iov[0].iov_base = (char *)pSMB;
1188 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1189 rc = SendReceive2(xid, tcon->ses, iov,
1190 1 /* num iovecs */,
1191 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001192 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001193 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 if (rc) {
1195 cERROR(1, ("Send error in read = %d", rc));
1196 } else {
1197 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1198 data_length = data_length << 16;
1199 data_length += le16_to_cpu(pSMBr->DataLength);
1200 *nbytes = data_length;
1201
1202 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001203 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 || (data_length > count)) {
1205 cFYI(1,("bad length %d for count %d",data_length,count));
1206 rc = -EIO;
1207 *nbytes = 0;
1208 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001209 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001211/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1212 cERROR(1,("Faulting on read rc = %d",rc));
1213 rc = -EFAULT;
1214 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001216 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 }
1218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
Steve French4b8f9302006-02-26 16:41:18 +00001220/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001221 if(*buf) {
1222 if(resp_buf_type == CIFS_SMALL_BUFFER)
1223 cifs_small_buf_release(iov[0].iov_base);
1224 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1225 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001226 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1227 /* return buffer to caller to free */
1228 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001229 if(resp_buf_type == CIFS_SMALL_BUFFER)
1230 *pbuf_type = CIFS_SMALL_BUFFER;
1231 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1232 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001233 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001234
1235 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 since file handle passed in no longer valid */
1237 return rc;
1238}
1239
Steve Frenchec637e32005-12-12 20:53:18 -08001240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241int
1242CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1243 const int netfid, const unsigned int count,
1244 const __u64 offset, unsigned int *nbytes, const char *buf,
1245 const char __user * ubuf, const int long_op)
1246{
1247 int rc = -EACCES;
1248 WRITE_REQ *pSMB = NULL;
1249 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001250 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 __u32 bytes_sent;
1252 __u16 byte_count;
1253
1254 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001255 if(tcon->ses == NULL)
1256 return -ECONNABORTED;
1257
1258 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1259 wct = 14;
1260 else
1261 wct = 12;
1262
1263 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 (void **) &pSMBr);
1265 if (rc)
1266 return rc;
1267 /* tcon and ses pointer are checked in smb_init */
1268 if (tcon->ses->server == NULL)
1269 return -ECONNABORTED;
1270
1271 pSMB->AndXCommand = 0xFF; /* none */
1272 pSMB->Fid = netfid;
1273 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001274 if(wct == 14)
1275 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1276 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1277 return -EIO;
1278
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 pSMB->Reserved = 0xFFFFFFFF;
1280 pSMB->WriteMode = 0;
1281 pSMB->Remaining = 0;
1282
1283 /* Can increase buffer size if buffer is big enough in some cases - ie we
1284 can send more if LARGE_WRITE_X capability returned by the server and if
1285 our buffer is big enough or if we convert to iovecs on socket writes
1286 and eliminate the copy to the CIFS buffer */
1287 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1288 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1289 } else {
1290 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1291 & ~0xFF;
1292 }
1293
1294 if (bytes_sent > count)
1295 bytes_sent = count;
1296 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001297 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 if(buf)
1299 memcpy(pSMB->Data,buf,bytes_sent);
1300 else if(ubuf) {
1301 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1302 cifs_buf_release(pSMB);
1303 return -EFAULT;
1304 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001305 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 /* No buffer */
1307 cifs_buf_release(pSMB);
1308 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001309 } /* else setting file size with write of zero bytes */
1310 if(wct == 14)
1311 byte_count = bytes_sent + 1; /* pad */
1312 else /* wct == 12 */ {
1313 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1316 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001317 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001318
1319 if(wct == 14)
1320 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001321 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001322 struct smb_com_writex_req * pSMBW =
1323 (struct smb_com_writex_req *)pSMB;
1324 pSMBW->ByteCount = cpu_to_le16(byte_count);
1325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
1327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1328 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001329 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 if (rc) {
1331 cFYI(1, ("Send error in write = %d", rc));
1332 *nbytes = 0;
1333 } else {
1334 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1335 *nbytes = (*nbytes) << 16;
1336 *nbytes += le16_to_cpu(pSMBr->Count);
1337 }
1338
1339 cifs_buf_release(pSMB);
1340
1341 /* Note: On -EAGAIN error only caller can retry on handle based calls
1342 since file handle passed in no longer valid */
1343
1344 return rc;
1345}
1346
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001347int
1348CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001350 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1351 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352{
1353 int rc = -EACCES;
1354 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001355 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001356 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001357 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Steve Frenchff7feac2005-11-15 16:45:16 -08001359 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1360
Steve French8cc64c62005-10-03 13:49:43 -07001361 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1362 wct = 14;
1363 else
1364 wct = 12;
1365 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 if (rc)
1367 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 /* tcon and ses pointer are checked in smb_init */
1369 if (tcon->ses->server == NULL)
1370 return -ECONNABORTED;
1371
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001372 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 pSMB->Fid = netfid;
1374 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001375 if(wct == 14)
1376 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1377 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1378 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 pSMB->Reserved = 0xFFFFFFFF;
1380 pSMB->WriteMode = 0;
1381 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001382
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 pSMB->DataOffset =
1384 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1385
Steve French3e844692005-10-03 13:37:24 -07001386 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1387 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001388 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001389 if(wct == 14)
1390 pSMB->hdr.smb_buf_length += count+1;
1391 else /* wct == 12 */
1392 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1393 if(wct == 14)
1394 pSMB->ByteCount = cpu_to_le16(count + 1);
1395 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1396 struct smb_com_writex_req * pSMBW =
1397 (struct smb_com_writex_req *)pSMB;
1398 pSMBW->ByteCount = cpu_to_le16(count + 5);
1399 }
Steve French3e844692005-10-03 13:37:24 -07001400 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001401 if(wct == 14)
1402 iov[0].iov_len = smb_hdr_len + 4;
1403 else /* wct == 12 pad bigger by four bytes */
1404 iov[0].iov_len = smb_hdr_len + 8;
1405
Steve French3e844692005-10-03 13:37:24 -07001406
Steve Frenchec637e32005-12-12 20:53:18 -08001407 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001408 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001409 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001411 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001413 } else if(resp_buf_type == 0) {
1414 /* presumably this can not happen, but best to be safe */
1415 rc = -EIO;
1416 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001417 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001418 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001419 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1420 *nbytes = (*nbytes) << 16;
1421 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Steve French4b8f9302006-02-26 16:41:18 +00001424/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001425 if(resp_buf_type == CIFS_SMALL_BUFFER)
1426 cifs_small_buf_release(iov[0].iov_base);
1427 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1428 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
1430 /* Note: On -EAGAIN error only caller can retry on handle based calls
1431 since file handle passed in no longer valid */
1432
1433 return rc;
1434}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001435
1436
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437int
1438CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1439 const __u16 smb_file_id, const __u64 len,
1440 const __u64 offset, const __u32 numUnlock,
1441 const __u32 numLock, const __u8 lockType, const int waitFlag)
1442{
1443 int rc = 0;
1444 LOCK_REQ *pSMB = NULL;
1445 LOCK_RSP *pSMBr = NULL;
1446 int bytes_returned;
1447 int timeout = 0;
1448 __u16 count;
1449
1450 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001451 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1452
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 if (rc)
1454 return rc;
1455
Steve French46810cb2005-04-28 22:41:09 -07001456 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1457
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1459 timeout = -1; /* no response expected */
1460 pSMB->Timeout = 0;
1461 } else if (waitFlag == TRUE) {
1462 timeout = 3; /* blocking operation, no timeout */
1463 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1464 } else {
1465 pSMB->Timeout = 0;
1466 }
1467
1468 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1469 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1470 pSMB->LockType = lockType;
1471 pSMB->AndXCommand = 0xFF; /* none */
1472 pSMB->Fid = smb_file_id; /* netfid stays le */
1473
1474 if((numLock != 0) || (numUnlock != 0)) {
1475 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1476 /* BB where to store pid high? */
1477 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1478 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1479 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1480 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1481 count = sizeof(LOCKING_ANDX_RANGE);
1482 } else {
1483 /* oplock break */
1484 count = 0;
1485 }
1486 pSMB->hdr.smb_buf_length += count;
1487 pSMB->ByteCount = cpu_to_le16(count);
1488
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001489 if (waitFlag) {
1490 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1491 (struct smb_hdr *) pSMBr, &bytes_returned);
1492 } else {
1493 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001495 }
Steve Frencha4544342005-08-24 13:59:35 -07001496 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 if (rc) {
1498 cFYI(1, ("Send error in Lock = %d", rc));
1499 }
Steve French46810cb2005-04-28 22:41:09 -07001500 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
1502 /* Note: On -EAGAIN error only caller can retry on handle based calls
1503 since file handle passed in no longer valid */
1504 return rc;
1505}
1506
1507int
Steve French08547b02006-02-28 22:39:25 +00001508CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1509 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001510 struct file_lock *pLockData, const __u16 lock_type,
1511 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001512{
1513 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1514 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1515 char *data_offset;
1516 struct cifs_posix_lock *parm_data;
1517 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001518 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001519 int bytes_returned = 0;
1520 __u16 params, param_offset, offset, byte_count, count;
1521
1522 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001523
1524 if(pLockData == NULL)
1525 return EINVAL;
1526
Steve French08547b02006-02-28 22:39:25 +00001527 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1528
1529 if (rc)
1530 return rc;
1531
1532 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1533
1534 params = 6;
1535 pSMB->MaxSetupCount = 0;
1536 pSMB->Reserved = 0;
1537 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001538 pSMB->Reserved2 = 0;
1539 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1540 offset = param_offset + params;
1541
1542 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1543
1544 count = sizeof(struct cifs_posix_lock);
1545 pSMB->MaxParameterCount = cpu_to_le16(2);
1546 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1547 pSMB->SetupCount = 1;
1548 pSMB->Reserved3 = 0;
1549 if(get_flag)
1550 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1551 else
1552 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1553 byte_count = 3 /* pad */ + params + count;
1554 pSMB->DataCount = cpu_to_le16(count);
1555 pSMB->ParameterCount = cpu_to_le16(params);
1556 pSMB->TotalDataCount = pSMB->DataCount;
1557 pSMB->TotalParameterCount = pSMB->ParameterCount;
1558 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1559 parm_data = (struct cifs_posix_lock *)
1560 (((char *) &pSMB->hdr.Protocol) + offset);
1561
1562 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French3a5ff612006-07-14 22:37:11 +00001563 if(waitFlag) {
1564 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001565 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001566 pSMB->Timeout = cpu_to_le32(-1);
1567 } else
1568 pSMB->Timeout = 0;
1569
Steve French08547b02006-02-28 22:39:25 +00001570 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001571 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001572 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001573
1574 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001575 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001576 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1577 pSMB->Reserved4 = 0;
1578 pSMB->hdr.smb_buf_length += byte_count;
1579 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001580 if (waitFlag) {
1581 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1582 (struct smb_hdr *) pSMBr, &bytes_returned);
1583 } else {
1584 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001585 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001586 }
1587
Steve French08547b02006-02-28 22:39:25 +00001588 if (rc) {
1589 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001590 } else if (get_flag) {
1591 /* lock structure can be returned on get */
1592 __u16 data_offset;
1593 __u16 data_count;
1594 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001595
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001596 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1597 rc = -EIO; /* bad smb */
1598 goto plk_err_exit;
1599 }
1600 if(pLockData == NULL) {
1601 rc = -EINVAL;
1602 goto plk_err_exit;
1603 }
1604 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1605 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1606 if(data_count < sizeof(struct cifs_posix_lock)) {
1607 rc = -EIO;
1608 goto plk_err_exit;
1609 }
1610 parm_data = (struct cifs_posix_lock *)
1611 ((char *)&pSMBr->hdr.Protocol + data_offset);
1612 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1613 pLockData->fl_type = F_UNLCK;
1614 }
1615
1616plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001617 if (pSMB)
1618 cifs_small_buf_release(pSMB);
1619
1620 /* Note: On -EAGAIN error only caller can retry on handle based calls
1621 since file handle passed in no longer valid */
1622
1623 return rc;
1624}
1625
1626
1627int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1629{
1630 int rc = 0;
1631 CLOSE_REQ *pSMB = NULL;
1632 CLOSE_RSP *pSMBr = NULL;
1633 int bytes_returned;
1634 cFYI(1, ("In CIFSSMBClose"));
1635
1636/* do not retry on dead session on close */
1637 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1638 if(rc == -EAGAIN)
1639 return 0;
1640 if (rc)
1641 return rc;
1642
1643 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1644
1645 pSMB->FileID = (__u16) smb_file_id;
1646 pSMB->LastWriteTime = 0;
1647 pSMB->ByteCount = 0;
1648 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1649 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001650 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 if (rc) {
1652 if(rc!=-EINTR) {
1653 /* EINTR is expected when user ctl-c to kill app */
1654 cERROR(1, ("Send error in Close = %d", rc));
1655 }
1656 }
1657
1658 cifs_small_buf_release(pSMB);
1659
1660 /* Since session is dead, file will be closed on server already */
1661 if(rc == -EAGAIN)
1662 rc = 0;
1663
1664 return rc;
1665}
1666
1667int
1668CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1669 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001670 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671{
1672 int rc = 0;
1673 RENAME_REQ *pSMB = NULL;
1674 RENAME_RSP *pSMBr = NULL;
1675 int bytes_returned;
1676 int name_len, name_len2;
1677 __u16 count;
1678
1679 cFYI(1, ("In CIFSSMBRename"));
1680renameRetry:
1681 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1682 (void **) &pSMBr);
1683 if (rc)
1684 return rc;
1685
1686 pSMB->BufferFormat = 0x04;
1687 pSMB->SearchAttributes =
1688 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1689 ATTR_DIRECTORY);
1690
1691 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1692 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001693 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001694 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 name_len++; /* trailing null */
1696 name_len *= 2;
1697 pSMB->OldFileName[name_len] = 0x04; /* pad */
1698 /* protocol requires ASCII signature byte on Unicode string */
1699 pSMB->OldFileName[name_len + 1] = 0x00;
1700 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001701 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001702 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1704 name_len2 *= 2; /* convert to bytes */
1705 } else { /* BB improve the check for buffer overruns BB */
1706 name_len = strnlen(fromName, PATH_MAX);
1707 name_len++; /* trailing null */
1708 strncpy(pSMB->OldFileName, fromName, name_len);
1709 name_len2 = strnlen(toName, PATH_MAX);
1710 name_len2++; /* trailing null */
1711 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1712 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1713 name_len2++; /* trailing null */
1714 name_len2++; /* signature byte */
1715 }
1716
1717 count = 1 /* 1st signature byte */ + name_len + name_len2;
1718 pSMB->hdr.smb_buf_length += count;
1719 pSMB->ByteCount = cpu_to_le16(count);
1720
1721 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1722 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001723 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 if (rc) {
1725 cFYI(1, ("Send error in rename = %d", rc));
1726 }
1727
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 cifs_buf_release(pSMB);
1729
1730 if (rc == -EAGAIN)
1731 goto renameRetry;
1732
1733 return rc;
1734}
1735
1736int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001737 int netfid, char * target_name,
1738 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739{
1740 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1741 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1742 struct set_file_rename * rename_info;
1743 char *data_offset;
1744 char dummy_string[30];
1745 int rc = 0;
1746 int bytes_returned = 0;
1747 int len_of_str;
1748 __u16 params, param_offset, offset, count, byte_count;
1749
1750 cFYI(1, ("Rename to File by handle"));
1751 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1752 (void **) &pSMBr);
1753 if (rc)
1754 return rc;
1755
1756 params = 6;
1757 pSMB->MaxSetupCount = 0;
1758 pSMB->Reserved = 0;
1759 pSMB->Flags = 0;
1760 pSMB->Timeout = 0;
1761 pSMB->Reserved2 = 0;
1762 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1763 offset = param_offset + params;
1764
1765 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1766 rename_info = (struct set_file_rename *) data_offset;
1767 pSMB->MaxParameterCount = cpu_to_le16(2);
1768 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1769 pSMB->SetupCount = 1;
1770 pSMB->Reserved3 = 0;
1771 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1772 byte_count = 3 /* pad */ + params;
1773 pSMB->ParameterCount = cpu_to_le16(params);
1774 pSMB->TotalParameterCount = pSMB->ParameterCount;
1775 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1776 pSMB->DataOffset = cpu_to_le16(offset);
1777 /* construct random name ".cifs_tmp<inodenum><mid>" */
1778 rename_info->overwrite = cpu_to_le32(1);
1779 rename_info->root_fid = 0;
1780 /* unicode only call */
1781 if(target_name == NULL) {
1782 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001783 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001784 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001786 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001787 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 }
1789 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1790 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1791 byte_count += count;
1792 pSMB->DataCount = cpu_to_le16(count);
1793 pSMB->TotalDataCount = pSMB->DataCount;
1794 pSMB->Fid = netfid;
1795 pSMB->InformationLevel =
1796 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1797 pSMB->Reserved4 = 0;
1798 pSMB->hdr.smb_buf_length += byte_count;
1799 pSMB->ByteCount = cpu_to_le16(byte_count);
1800 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1801 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001802 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 if (rc) {
1804 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1805 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001806
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 cifs_buf_release(pSMB);
1808
1809 /* Note: On -EAGAIN error only caller can retry on handle based calls
1810 since file handle passed in no longer valid */
1811
1812 return rc;
1813}
1814
1815int
1816CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1817 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001818 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819{
1820 int rc = 0;
1821 COPY_REQ *pSMB = NULL;
1822 COPY_RSP *pSMBr = NULL;
1823 int bytes_returned;
1824 int name_len, name_len2;
1825 __u16 count;
1826
1827 cFYI(1, ("In CIFSSMBCopy"));
1828copyRetry:
1829 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1830 (void **) &pSMBr);
1831 if (rc)
1832 return rc;
1833
1834 pSMB->BufferFormat = 0x04;
1835 pSMB->Tid2 = target_tid;
1836
1837 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1838
1839 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001840 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001841 fromName, PATH_MAX, nls_codepage,
1842 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 name_len++; /* trailing null */
1844 name_len *= 2;
1845 pSMB->OldFileName[name_len] = 0x04; /* pad */
1846 /* protocol requires ASCII signature byte on Unicode string */
1847 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001848 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001849 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1851 name_len2 *= 2; /* convert to bytes */
1852 } else { /* BB improve the check for buffer overruns BB */
1853 name_len = strnlen(fromName, PATH_MAX);
1854 name_len++; /* trailing null */
1855 strncpy(pSMB->OldFileName, fromName, name_len);
1856 name_len2 = strnlen(toName, PATH_MAX);
1857 name_len2++; /* trailing null */
1858 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1859 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1860 name_len2++; /* trailing null */
1861 name_len2++; /* signature byte */
1862 }
1863
1864 count = 1 /* 1st signature byte */ + name_len + name_len2;
1865 pSMB->hdr.smb_buf_length += count;
1866 pSMB->ByteCount = cpu_to_le16(count);
1867
1868 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1869 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1870 if (rc) {
1871 cFYI(1, ("Send error in copy = %d with %d files copied",
1872 rc, le16_to_cpu(pSMBr->CopyCount)));
1873 }
1874 if (pSMB)
1875 cifs_buf_release(pSMB);
1876
1877 if (rc == -EAGAIN)
1878 goto copyRetry;
1879
1880 return rc;
1881}
1882
1883int
1884CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1885 const char *fromName, const char *toName,
1886 const struct nls_table *nls_codepage)
1887{
1888 TRANSACTION2_SPI_REQ *pSMB = NULL;
1889 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1890 char *data_offset;
1891 int name_len;
1892 int name_len_target;
1893 int rc = 0;
1894 int bytes_returned = 0;
1895 __u16 params, param_offset, offset, byte_count;
1896
1897 cFYI(1, ("In Symlink Unix style"));
1898createSymLinkRetry:
1899 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1900 (void **) &pSMBr);
1901 if (rc)
1902 return rc;
1903
1904 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1905 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001906 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 /* find define for this maxpathcomponent */
1908 , nls_codepage);
1909 name_len++; /* trailing null */
1910 name_len *= 2;
1911
1912 } else { /* BB improve the check for buffer overruns BB */
1913 name_len = strnlen(fromName, PATH_MAX);
1914 name_len++; /* trailing null */
1915 strncpy(pSMB->FileName, fromName, name_len);
1916 }
1917 params = 6 + name_len;
1918 pSMB->MaxSetupCount = 0;
1919 pSMB->Reserved = 0;
1920 pSMB->Flags = 0;
1921 pSMB->Timeout = 0;
1922 pSMB->Reserved2 = 0;
1923 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1924 InformationLevel) - 4;
1925 offset = param_offset + params;
1926
1927 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1928 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1929 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001930 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 /* find define for this maxpathcomponent */
1932 , nls_codepage);
1933 name_len_target++; /* trailing null */
1934 name_len_target *= 2;
1935 } else { /* BB improve the check for buffer overruns BB */
1936 name_len_target = strnlen(toName, PATH_MAX);
1937 name_len_target++; /* trailing null */
1938 strncpy(data_offset, toName, name_len_target);
1939 }
1940
1941 pSMB->MaxParameterCount = cpu_to_le16(2);
1942 /* BB find exact max on data count below from sess */
1943 pSMB->MaxDataCount = cpu_to_le16(1000);
1944 pSMB->SetupCount = 1;
1945 pSMB->Reserved3 = 0;
1946 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1947 byte_count = 3 /* pad */ + params + name_len_target;
1948 pSMB->DataCount = cpu_to_le16(name_len_target);
1949 pSMB->ParameterCount = cpu_to_le16(params);
1950 pSMB->TotalDataCount = pSMB->DataCount;
1951 pSMB->TotalParameterCount = pSMB->ParameterCount;
1952 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1953 pSMB->DataOffset = cpu_to_le16(offset);
1954 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1955 pSMB->Reserved4 = 0;
1956 pSMB->hdr.smb_buf_length += byte_count;
1957 pSMB->ByteCount = cpu_to_le16(byte_count);
1958 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1959 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001960 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 if (rc) {
1962 cFYI(1,
1963 ("Send error in SetPathInfo (create symlink) = %d",
1964 rc));
1965 }
1966
1967 if (pSMB)
1968 cifs_buf_release(pSMB);
1969
1970 if (rc == -EAGAIN)
1971 goto createSymLinkRetry;
1972
1973 return rc;
1974}
1975
1976int
1977CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1978 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001979 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980{
1981 TRANSACTION2_SPI_REQ *pSMB = NULL;
1982 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1983 char *data_offset;
1984 int name_len;
1985 int name_len_target;
1986 int rc = 0;
1987 int bytes_returned = 0;
1988 __u16 params, param_offset, offset, byte_count;
1989
1990 cFYI(1, ("In Create Hard link Unix style"));
1991createHardLinkRetry:
1992 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1993 (void **) &pSMBr);
1994 if (rc)
1995 return rc;
1996
1997 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001998 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001999 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 name_len++; /* trailing null */
2001 name_len *= 2;
2002
2003 } else { /* BB improve the check for buffer overruns BB */
2004 name_len = strnlen(toName, PATH_MAX);
2005 name_len++; /* trailing null */
2006 strncpy(pSMB->FileName, toName, name_len);
2007 }
2008 params = 6 + name_len;
2009 pSMB->MaxSetupCount = 0;
2010 pSMB->Reserved = 0;
2011 pSMB->Flags = 0;
2012 pSMB->Timeout = 0;
2013 pSMB->Reserved2 = 0;
2014 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2015 InformationLevel) - 4;
2016 offset = param_offset + params;
2017
2018 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2019 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2020 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002021 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002022 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 name_len_target++; /* trailing null */
2024 name_len_target *= 2;
2025 } else { /* BB improve the check for buffer overruns BB */
2026 name_len_target = strnlen(fromName, PATH_MAX);
2027 name_len_target++; /* trailing null */
2028 strncpy(data_offset, fromName, name_len_target);
2029 }
2030
2031 pSMB->MaxParameterCount = cpu_to_le16(2);
2032 /* BB find exact max on data count below from sess*/
2033 pSMB->MaxDataCount = cpu_to_le16(1000);
2034 pSMB->SetupCount = 1;
2035 pSMB->Reserved3 = 0;
2036 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2037 byte_count = 3 /* pad */ + params + name_len_target;
2038 pSMB->ParameterCount = cpu_to_le16(params);
2039 pSMB->TotalParameterCount = pSMB->ParameterCount;
2040 pSMB->DataCount = cpu_to_le16(name_len_target);
2041 pSMB->TotalDataCount = pSMB->DataCount;
2042 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2043 pSMB->DataOffset = cpu_to_le16(offset);
2044 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2045 pSMB->Reserved4 = 0;
2046 pSMB->hdr.smb_buf_length += byte_count;
2047 pSMB->ByteCount = cpu_to_le16(byte_count);
2048 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2049 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002050 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 if (rc) {
2052 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2053 }
2054
2055 cifs_buf_release(pSMB);
2056 if (rc == -EAGAIN)
2057 goto createHardLinkRetry;
2058
2059 return rc;
2060}
2061
2062int
2063CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2064 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002065 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066{
2067 int rc = 0;
2068 NT_RENAME_REQ *pSMB = NULL;
2069 RENAME_RSP *pSMBr = NULL;
2070 int bytes_returned;
2071 int name_len, name_len2;
2072 __u16 count;
2073
2074 cFYI(1, ("In CIFSCreateHardLink"));
2075winCreateHardLinkRetry:
2076
2077 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2078 (void **) &pSMBr);
2079 if (rc)
2080 return rc;
2081
2082 pSMB->SearchAttributes =
2083 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2084 ATTR_DIRECTORY);
2085 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2086 pSMB->ClusterCount = 0;
2087
2088 pSMB->BufferFormat = 0x04;
2089
2090 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2091 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002092 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002093 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 name_len++; /* trailing null */
2095 name_len *= 2;
2096 pSMB->OldFileName[name_len] = 0; /* pad */
2097 pSMB->OldFileName[name_len + 1] = 0x04;
2098 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002099 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002100 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2102 name_len2 *= 2; /* convert to bytes */
2103 } else { /* BB improve the check for buffer overruns BB */
2104 name_len = strnlen(fromName, PATH_MAX);
2105 name_len++; /* trailing null */
2106 strncpy(pSMB->OldFileName, fromName, name_len);
2107 name_len2 = strnlen(toName, PATH_MAX);
2108 name_len2++; /* trailing null */
2109 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2110 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2111 name_len2++; /* trailing null */
2112 name_len2++; /* signature byte */
2113 }
2114
2115 count = 1 /* string type byte */ + name_len + name_len2;
2116 pSMB->hdr.smb_buf_length += count;
2117 pSMB->ByteCount = cpu_to_le16(count);
2118
2119 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2120 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002121 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 if (rc) {
2123 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2124 }
2125 cifs_buf_release(pSMB);
2126 if (rc == -EAGAIN)
2127 goto winCreateHardLinkRetry;
2128
2129 return rc;
2130}
2131
2132int
2133CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2134 const unsigned char *searchName,
2135 char *symlinkinfo, const int buflen,
2136 const struct nls_table *nls_codepage)
2137{
2138/* SMB_QUERY_FILE_UNIX_LINK */
2139 TRANSACTION2_QPI_REQ *pSMB = NULL;
2140 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2141 int rc = 0;
2142 int bytes_returned;
2143 int name_len;
2144 __u16 params, byte_count;
2145
2146 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2147
2148querySymLinkRetry:
2149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2150 (void **) &pSMBr);
2151 if (rc)
2152 return rc;
2153
2154 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2155 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002156 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 /* find define for this maxpathcomponent */
2158 , nls_codepage);
2159 name_len++; /* trailing null */
2160 name_len *= 2;
2161 } else { /* BB improve the check for buffer overruns BB */
2162 name_len = strnlen(searchName, PATH_MAX);
2163 name_len++; /* trailing null */
2164 strncpy(pSMB->FileName, searchName, name_len);
2165 }
2166
2167 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2168 pSMB->TotalDataCount = 0;
2169 pSMB->MaxParameterCount = cpu_to_le16(2);
2170 /* BB find exact max data count below from sess structure BB */
2171 pSMB->MaxDataCount = cpu_to_le16(4000);
2172 pSMB->MaxSetupCount = 0;
2173 pSMB->Reserved = 0;
2174 pSMB->Flags = 0;
2175 pSMB->Timeout = 0;
2176 pSMB->Reserved2 = 0;
2177 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2178 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2179 pSMB->DataCount = 0;
2180 pSMB->DataOffset = 0;
2181 pSMB->SetupCount = 1;
2182 pSMB->Reserved3 = 0;
2183 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2184 byte_count = params + 1 /* pad */ ;
2185 pSMB->TotalParameterCount = cpu_to_le16(params);
2186 pSMB->ParameterCount = pSMB->TotalParameterCount;
2187 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2188 pSMB->Reserved4 = 0;
2189 pSMB->hdr.smb_buf_length += byte_count;
2190 pSMB->ByteCount = cpu_to_le16(byte_count);
2191
2192 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2193 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2194 if (rc) {
2195 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2196 } else {
2197 /* decode response */
2198
2199 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2200 if (rc || (pSMBr->ByteCount < 2))
2201 /* BB also check enough total bytes returned */
2202 rc = -EIO; /* bad smb */
2203 else {
2204 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2205 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2206
2207 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2208 name_len = UniStrnlen((wchar_t *) ((char *)
2209 &pSMBr->hdr.Protocol +data_offset),
2210 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002211 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002213 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 data_offset),
2215 name_len, nls_codepage);
2216 } else {
2217 strncpy(symlinkinfo,
2218 (char *) &pSMBr->hdr.Protocol +
2219 data_offset,
2220 min_t(const int, buflen, count));
2221 }
2222 symlinkinfo[buflen] = 0;
2223 /* just in case so calling code does not go off the end of buffer */
2224 }
2225 }
2226 cifs_buf_release(pSMB);
2227 if (rc == -EAGAIN)
2228 goto querySymLinkRetry;
2229 return rc;
2230}
2231
Steve French0a4b92c2006-01-12 15:44:21 -08002232/* Initialize NT TRANSACT SMB into small smb request buffer.
2233 This assumes that all NT TRANSACTS that we init here have
2234 total parm and data under about 400 bytes (to fit in small cifs
2235 buffer size), which is the case so far, it easily fits. NB:
2236 Setup words themselves and ByteCount
2237 MaxSetupCount (size of returned setup area) and
2238 MaxParameterCount (returned parms size) must be set by caller */
2239static int
2240smb_init_ntransact(const __u16 sub_command, const int setup_count,
2241 const int parm_len, struct cifsTconInfo *tcon,
2242 void ** ret_buf)
2243{
2244 int rc;
2245 __u32 temp_offset;
2246 struct smb_com_ntransact_req * pSMB;
2247
2248 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2249 (void **)&pSMB);
2250 if (rc)
2251 return rc;
2252 *ret_buf = (void *)pSMB;
2253 pSMB->Reserved = 0;
2254 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2255 pSMB->TotalDataCount = 0;
2256 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2257 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2258 pSMB->ParameterCount = pSMB->TotalParameterCount;
2259 pSMB->DataCount = pSMB->TotalDataCount;
2260 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2261 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2262 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2263 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2264 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2265 pSMB->SubCommand = cpu_to_le16(sub_command);
2266 return 0;
2267}
2268
2269static int
2270validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2271 int * pdatalen, int * pparmlen)
2272{
2273 char * end_of_smb;
2274 __u32 data_count, data_offset, parm_count, parm_offset;
2275 struct smb_com_ntransact_rsp * pSMBr;
2276
2277 if(buf == NULL)
2278 return -EINVAL;
2279
2280 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2281
2282 /* ByteCount was converted from little endian in SendReceive */
2283 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2284 (char *)&pSMBr->ByteCount;
2285
2286
2287 data_offset = le32_to_cpu(pSMBr->DataOffset);
2288 data_count = le32_to_cpu(pSMBr->DataCount);
2289 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2290 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2291
2292 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2293 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2294
2295 /* should we also check that parm and data areas do not overlap? */
2296 if(*ppparm > end_of_smb) {
2297 cFYI(1,("parms start after end of smb"));
2298 return -EINVAL;
2299 } else if(parm_count + *ppparm > end_of_smb) {
2300 cFYI(1,("parm end after end of smb"));
2301 return -EINVAL;
2302 } else if(*ppdata > end_of_smb) {
2303 cFYI(1,("data starts after end of smb"));
2304 return -EINVAL;
2305 } else if(data_count + *ppdata > end_of_smb) {
2306 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2307 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2308 return -EINVAL;
2309 } else if(parm_count + data_count > pSMBr->ByteCount) {
2310 cFYI(1,("parm count and data count larger than SMB"));
2311 return -EINVAL;
2312 }
2313 return 0;
2314}
2315
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316int
2317CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2318 const unsigned char *searchName,
2319 char *symlinkinfo, const int buflen,__u16 fid,
2320 const struct nls_table *nls_codepage)
2321{
2322 int rc = 0;
2323 int bytes_returned;
2324 int name_len;
2325 struct smb_com_transaction_ioctl_req * pSMB;
2326 struct smb_com_transaction_ioctl_rsp * pSMBr;
2327
2328 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2329 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2330 (void **) &pSMBr);
2331 if (rc)
2332 return rc;
2333
2334 pSMB->TotalParameterCount = 0 ;
2335 pSMB->TotalDataCount = 0;
2336 pSMB->MaxParameterCount = cpu_to_le32(2);
2337 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002338 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2339 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 pSMB->MaxSetupCount = 4;
2341 pSMB->Reserved = 0;
2342 pSMB->ParameterOffset = 0;
2343 pSMB->DataCount = 0;
2344 pSMB->DataOffset = 0;
2345 pSMB->SetupCount = 4;
2346 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2347 pSMB->ParameterCount = pSMB->TotalParameterCount;
2348 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2349 pSMB->IsFsctl = 1; /* FSCTL */
2350 pSMB->IsRootFlag = 0;
2351 pSMB->Fid = fid; /* file handle always le */
2352 pSMB->ByteCount = 0;
2353
2354 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2355 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2356 if (rc) {
2357 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2358 } else { /* decode response */
2359 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2360 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2361 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2362 /* BB also check enough total bytes returned */
2363 rc = -EIO; /* bad smb */
2364 else {
2365 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002366 char * end_of_smb = 2 /* sizeof byte count */ +
2367 pSMBr->ByteCount +
2368 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
2370 struct reparse_data * reparse_buf = (struct reparse_data *)
2371 ((char *)&pSMBr->hdr.Protocol + data_offset);
2372 if((char*)reparse_buf >= end_of_smb) {
2373 rc = -EIO;
2374 goto qreparse_out;
2375 }
2376 if((reparse_buf->LinkNamesBuf +
2377 reparse_buf->TargetNameOffset +
2378 reparse_buf->TargetNameLen) >
2379 end_of_smb) {
2380 cFYI(1,("reparse buf extended beyond SMB"));
2381 rc = -EIO;
2382 goto qreparse_out;
2383 }
2384
2385 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2386 name_len = UniStrnlen((wchar_t *)
2387 (reparse_buf->LinkNamesBuf +
2388 reparse_buf->TargetNameOffset),
2389 min(buflen/2, reparse_buf->TargetNameLen / 2));
2390 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002391 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 reparse_buf->TargetNameOffset),
2393 name_len, nls_codepage);
2394 } else { /* ASCII names */
2395 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2396 reparse_buf->TargetNameOffset,
2397 min_t(const int, buflen, reparse_buf->TargetNameLen));
2398 }
2399 } else {
2400 rc = -EIO;
2401 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2402 }
2403 symlinkinfo[buflen] = 0; /* just in case so the caller
2404 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002405 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 }
2407 }
2408qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002409 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
2411 /* Note: On -EAGAIN error only caller can retry on handle based calls
2412 since file handle passed in no longer valid */
2413
2414 return rc;
2415}
2416
2417#ifdef CONFIG_CIFS_POSIX
2418
2419/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2420static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2421{
2422 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002423 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2424 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2425 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2427
2428 return;
2429}
2430
2431/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002432static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2433 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434{
2435 int size = 0;
2436 int i;
2437 __u16 count;
2438 struct cifs_posix_ace * pACE;
2439 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2440 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2441
2442 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2443 return -EOPNOTSUPP;
2444
2445 if(acl_type & ACL_TYPE_ACCESS) {
2446 count = le16_to_cpu(cifs_acl->access_entry_count);
2447 pACE = &cifs_acl->ace_array[0];
2448 size = sizeof(struct cifs_posix_acl);
2449 size += sizeof(struct cifs_posix_ace) * count;
2450 /* check if we would go beyond end of SMB */
2451 if(size_of_data_area < size) {
2452 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2453 return -EINVAL;
2454 }
2455 } else if(acl_type & ACL_TYPE_DEFAULT) {
2456 count = le16_to_cpu(cifs_acl->access_entry_count);
2457 size = sizeof(struct cifs_posix_acl);
2458 size += sizeof(struct cifs_posix_ace) * count;
2459/* skip past access ACEs to get to default ACEs */
2460 pACE = &cifs_acl->ace_array[count];
2461 count = le16_to_cpu(cifs_acl->default_entry_count);
2462 size += sizeof(struct cifs_posix_ace) * count;
2463 /* check if we would go beyond end of SMB */
2464 if(size_of_data_area < size)
2465 return -EINVAL;
2466 } else {
2467 /* illegal type */
2468 return -EINVAL;
2469 }
2470
2471 size = posix_acl_xattr_size(count);
2472 if((buflen == 0) || (local_acl == NULL)) {
2473 /* used to query ACL EA size */
2474 } else if(size > buflen) {
2475 return -ERANGE;
2476 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002477 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 for(i = 0;i < count ;i++) {
2479 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2480 pACE ++;
2481 }
2482 }
2483 return size;
2484}
2485
2486static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2487 const posix_acl_xattr_entry * local_ace)
2488{
2489 __u16 rc = 0; /* 0 = ACL converted ok */
2490
Steve Frenchff7feac2005-11-15 16:45:16 -08002491 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2492 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002494 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 /* Probably no need to le convert -1 on any arch but can not hurt */
2496 cifs_ace->cifs_uid = cpu_to_le64(-1);
2497 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002498 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2500 return rc;
2501}
2502
2503/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2504static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2505 const int acl_type)
2506{
2507 __u16 rc = 0;
2508 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2509 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2510 int count;
2511 int i;
2512
2513 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2514 return 0;
2515
2516 count = posix_acl_xattr_count((size_t)buflen);
2517 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002518 count, buflen, le32_to_cpu(local_acl->a_version)));
2519 if(le32_to_cpu(local_acl->a_version) != 2) {
2520 cFYI(1,("unknown POSIX ACL version %d",
2521 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 return 0;
2523 }
2524 cifs_acl->version = cpu_to_le16(1);
2525 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002526 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002528 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 else {
2530 cFYI(1,("unknown ACL type %d",acl_type));
2531 return 0;
2532 }
2533 for(i=0;i<count;i++) {
2534 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2535 &local_acl->a_entries[i]);
2536 if(rc != 0) {
2537 /* ACE not converted */
2538 break;
2539 }
2540 }
2541 if(rc == 0) {
2542 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2543 rc += sizeof(struct cifs_posix_acl);
2544 /* BB add check to make sure ACL does not overflow SMB */
2545 }
2546 return rc;
2547}
2548
2549int
2550CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2551 const unsigned char *searchName,
2552 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002553 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554{
2555/* SMB_QUERY_POSIX_ACL */
2556 TRANSACTION2_QPI_REQ *pSMB = NULL;
2557 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2558 int rc = 0;
2559 int bytes_returned;
2560 int name_len;
2561 __u16 params, byte_count;
2562
2563 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2564
2565queryAclRetry:
2566 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2567 (void **) &pSMBr);
2568 if (rc)
2569 return rc;
2570
2571 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2572 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002573 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002574 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 name_len++; /* trailing null */
2576 name_len *= 2;
2577 pSMB->FileName[name_len] = 0;
2578 pSMB->FileName[name_len+1] = 0;
2579 } else { /* BB improve the check for buffer overruns BB */
2580 name_len = strnlen(searchName, PATH_MAX);
2581 name_len++; /* trailing null */
2582 strncpy(pSMB->FileName, searchName, name_len);
2583 }
2584
2585 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2586 pSMB->TotalDataCount = 0;
2587 pSMB->MaxParameterCount = cpu_to_le16(2);
2588 /* BB find exact max data count below from sess structure BB */
2589 pSMB->MaxDataCount = cpu_to_le16(4000);
2590 pSMB->MaxSetupCount = 0;
2591 pSMB->Reserved = 0;
2592 pSMB->Flags = 0;
2593 pSMB->Timeout = 0;
2594 pSMB->Reserved2 = 0;
2595 pSMB->ParameterOffset = cpu_to_le16(
2596 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2597 pSMB->DataCount = 0;
2598 pSMB->DataOffset = 0;
2599 pSMB->SetupCount = 1;
2600 pSMB->Reserved3 = 0;
2601 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2602 byte_count = params + 1 /* pad */ ;
2603 pSMB->TotalParameterCount = cpu_to_le16(params);
2604 pSMB->ParameterCount = pSMB->TotalParameterCount;
2605 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2606 pSMB->Reserved4 = 0;
2607 pSMB->hdr.smb_buf_length += byte_count;
2608 pSMB->ByteCount = cpu_to_le16(byte_count);
2609
2610 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2611 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002612 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 if (rc) {
2614 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2615 } else {
2616 /* decode response */
2617
2618 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2619 if (rc || (pSMBr->ByteCount < 2))
2620 /* BB also check enough total bytes returned */
2621 rc = -EIO; /* bad smb */
2622 else {
2623 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2624 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2625 rc = cifs_copy_posix_acl(acl_inf,
2626 (char *)&pSMBr->hdr.Protocol+data_offset,
2627 buflen,acl_type,count);
2628 }
2629 }
2630 cifs_buf_release(pSMB);
2631 if (rc == -EAGAIN)
2632 goto queryAclRetry;
2633 return rc;
2634}
2635
2636int
2637CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2638 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002639 const char *local_acl, const int buflen,
2640 const int acl_type,
2641 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642{
2643 struct smb_com_transaction2_spi_req *pSMB = NULL;
2644 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2645 char *parm_data;
2646 int name_len;
2647 int rc = 0;
2648 int bytes_returned = 0;
2649 __u16 params, byte_count, data_count, param_offset, offset;
2650
2651 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2652setAclRetry:
2653 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2654 (void **) &pSMBr);
2655 if (rc)
2656 return rc;
2657 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2658 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002659 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002660 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 name_len++; /* trailing null */
2662 name_len *= 2;
2663 } else { /* BB improve the check for buffer overruns BB */
2664 name_len = strnlen(fileName, PATH_MAX);
2665 name_len++; /* trailing null */
2666 strncpy(pSMB->FileName, fileName, name_len);
2667 }
2668 params = 6 + name_len;
2669 pSMB->MaxParameterCount = cpu_to_le16(2);
2670 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2671 pSMB->MaxSetupCount = 0;
2672 pSMB->Reserved = 0;
2673 pSMB->Flags = 0;
2674 pSMB->Timeout = 0;
2675 pSMB->Reserved2 = 0;
2676 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2677 InformationLevel) - 4;
2678 offset = param_offset + params;
2679 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2680 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2681
2682 /* convert to on the wire format for POSIX ACL */
2683 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2684
2685 if(data_count == 0) {
2686 rc = -EOPNOTSUPP;
2687 goto setACLerrorExit;
2688 }
2689 pSMB->DataOffset = cpu_to_le16(offset);
2690 pSMB->SetupCount = 1;
2691 pSMB->Reserved3 = 0;
2692 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2693 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2694 byte_count = 3 /* pad */ + params + data_count;
2695 pSMB->DataCount = cpu_to_le16(data_count);
2696 pSMB->TotalDataCount = pSMB->DataCount;
2697 pSMB->ParameterCount = cpu_to_le16(params);
2698 pSMB->TotalParameterCount = pSMB->ParameterCount;
2699 pSMB->Reserved4 = 0;
2700 pSMB->hdr.smb_buf_length += byte_count;
2701 pSMB->ByteCount = cpu_to_le16(byte_count);
2702 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2703 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2704 if (rc) {
2705 cFYI(1, ("Set POSIX ACL returned %d", rc));
2706 }
2707
2708setACLerrorExit:
2709 cifs_buf_release(pSMB);
2710 if (rc == -EAGAIN)
2711 goto setAclRetry;
2712 return rc;
2713}
2714
Steve Frenchf654bac2005-04-28 22:41:04 -07002715/* BB fix tabs in this function FIXME BB */
2716int
2717CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2718 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2719{
2720 int rc = 0;
2721 struct smb_t2_qfi_req *pSMB = NULL;
2722 struct smb_t2_qfi_rsp *pSMBr = NULL;
2723 int bytes_returned;
2724 __u16 params, byte_count;
2725
2726 cFYI(1,("In GetExtAttr"));
2727 if(tcon == NULL)
2728 return -ENODEV;
2729
2730GetExtAttrRetry:
2731 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2732 (void **) &pSMBr);
2733 if (rc)
2734 return rc;
2735
Steve Frenchc67593a2005-04-28 22:41:04 -07002736 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002737 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002738 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002739 /* BB find exact max data count below from sess structure BB */
2740 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2741 pSMB->t2.MaxSetupCount = 0;
2742 pSMB->t2.Reserved = 0;
2743 pSMB->t2.Flags = 0;
2744 pSMB->t2.Timeout = 0;
2745 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002746 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2747 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002748 pSMB->t2.DataCount = 0;
2749 pSMB->t2.DataOffset = 0;
2750 pSMB->t2.SetupCount = 1;
2751 pSMB->t2.Reserved3 = 0;
2752 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002753 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002754 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2755 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2756 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002757 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002758 pSMB->Fid = netfid;
2759 pSMB->hdr.smb_buf_length += byte_count;
2760 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2761
2762 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2763 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2764 if (rc) {
2765 cFYI(1, ("error %d in GetExtAttr", rc));
2766 } else {
2767 /* decode response */
2768 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2769 if (rc || (pSMBr->ByteCount < 2))
2770 /* BB also check enough total bytes returned */
2771 /* If rc should we check for EOPNOSUPP and
2772 disable the srvino flag? or in caller? */
2773 rc = -EIO; /* bad smb */
2774 else {
2775 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2776 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2777 struct file_chattr_info * pfinfo;
2778 /* BB Do we need a cast or hash here ? */
2779 if(count != 16) {
2780 cFYI(1, ("Illegal size ret in GetExtAttr"));
2781 rc = -EIO;
2782 goto GetExtAttrOut;
2783 }
2784 pfinfo = (struct file_chattr_info *)
2785 (data_offset + (char *) &pSMBr->hdr.Protocol);
2786 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2787 *pMask = le64_to_cpu(pfinfo->mask);
2788 }
2789 }
2790GetExtAttrOut:
2791 cifs_buf_release(pSMB);
2792 if (rc == -EAGAIN)
2793 goto GetExtAttrRetry;
2794 return rc;
2795}
2796
2797
2798#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799
Steve Frencheeac8042006-01-13 21:34:58 -08002800
2801/* security id for everyone */
Steve French2cd646a2006-09-28 19:43:08 +00002802const static struct cifs_sid sid_everyone =
2803 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002804/* group users */
Steve French2cd646a2006-09-28 19:43:08 +00002805const static struct cifs_sid sid_user =
2806 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002807
Steve French0a4b92c2006-01-12 15:44:21 -08002808/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002809static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002810{
Steve French0a4b92c2006-01-12 15:44:21 -08002811 return 0;
2812}
2813
2814/* Get Security Descriptor (by handle) from remote server for a file or dir */
2815int
2816CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2817 /* BB fix up return info */ char *acl_inf, const int buflen,
2818 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2819{
2820 int rc = 0;
2821 int buf_type = 0;
2822 QUERY_SEC_DESC_REQ * pSMB;
2823 struct kvec iov[1];
2824
2825 cFYI(1, ("GetCifsACL"));
2826
2827 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2828 8 /* parm len */, tcon, (void **) &pSMB);
2829 if (rc)
2830 return rc;
2831
2832 pSMB->MaxParameterCount = cpu_to_le32(4);
2833 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2834 pSMB->MaxSetupCount = 0;
2835 pSMB->Fid = fid; /* file handle always le */
2836 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2837 CIFS_ACL_DACL);
2838 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2839 pSMB->hdr.smb_buf_length += 11;
2840 iov[0].iov_base = (char *)pSMB;
2841 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2842
2843 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2844 cifs_stats_inc(&tcon->num_acl_get);
2845 if (rc) {
2846 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2847 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002848 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002849 __le32 * parm;
2850 int parm_len;
2851 int data_len;
2852 int acl_len;
2853 struct smb_com_ntransact_rsp * pSMBr;
2854
2855/* validate_nttransact */
2856 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2857 (char **)&psec_desc,
2858 &parm_len, &data_len);
2859
2860 if(rc)
2861 goto qsec_out;
2862 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2863
2864 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2865
2866 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2867 rc = -EIO; /* bad smb */
2868 goto qsec_out;
2869 }
2870
2871/* BB check that data area is minimum length and as big as acl_len */
2872
2873 acl_len = le32_to_cpu(*(__le32 *)parm);
2874 /* BB check if(acl_len > bufsize) */
2875
2876 parse_sec_desc(psec_desc, acl_len);
2877 }
2878qsec_out:
2879 if(buf_type == CIFS_SMALL_BUFFER)
2880 cifs_small_buf_release(iov[0].iov_base);
2881 else if(buf_type == CIFS_LARGE_BUFFER)
2882 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002883/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002884 return rc;
2885}
2886
Steve French6b8edfe2005-08-23 20:26:03 -07002887/* Legacy Query Path Information call for lookup to old servers such
2888 as Win9x/WinME */
2889int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2890 const unsigned char *searchName,
2891 FILE_ALL_INFO * pFinfo,
2892 const struct nls_table *nls_codepage, int remap)
2893{
2894 QUERY_INFORMATION_REQ * pSMB;
2895 QUERY_INFORMATION_RSP * pSMBr;
2896 int rc = 0;
2897 int bytes_returned;
2898 int name_len;
2899
2900 cFYI(1, ("In SMBQPath path %s", searchName));
2901QInfRetry:
2902 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2903 (void **) &pSMBr);
2904 if (rc)
2905 return rc;
2906
2907 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2908 name_len =
2909 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2910 PATH_MAX, nls_codepage, remap);
2911 name_len++; /* trailing null */
2912 name_len *= 2;
2913 } else {
2914 name_len = strnlen(searchName, PATH_MAX);
2915 name_len++; /* trailing null */
2916 strncpy(pSMB->FileName, searchName, name_len);
2917 }
2918 pSMB->BufferFormat = 0x04;
2919 name_len++; /* account for buffer type byte */
2920 pSMB->hdr.smb_buf_length += (__u16) name_len;
2921 pSMB->ByteCount = cpu_to_le16(name_len);
2922
2923 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2925 if (rc) {
2926 cFYI(1, ("Send error in QueryInfo = %d", rc));
2927 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00002928 struct timespec ts;
2929 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2930 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07002931 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00002932 ts.tv_nsec = 0;
2933 ts.tv_sec = time;
2934 /* decode time fields */
2935 pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
2936 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2937 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07002938 pFinfo->AllocationSize =
2939 cpu_to_le64(le32_to_cpu(pSMBr->size));
2940 pFinfo->EndOfFile = pFinfo->AllocationSize;
2941 pFinfo->Attributes =
2942 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002943 } else
2944 rc = -EIO; /* bad buffer passed in */
2945
2946 cifs_buf_release(pSMB);
2947
2948 if (rc == -EAGAIN)
2949 goto QInfRetry;
2950
2951 return rc;
2952}
2953
2954
2955
2956
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957int
2958CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2959 const unsigned char *searchName,
2960 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002961 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962{
2963/* level 263 SMB_QUERY_FILE_ALL_INFO */
2964 TRANSACTION2_QPI_REQ *pSMB = NULL;
2965 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2966 int rc = 0;
2967 int bytes_returned;
2968 int name_len;
2969 __u16 params, byte_count;
2970
2971/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2972QPathInfoRetry:
2973 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2974 (void **) &pSMBr);
2975 if (rc)
2976 return rc;
2977
2978 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2979 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002980 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002981 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 name_len++; /* trailing null */
2983 name_len *= 2;
2984 } else { /* BB improve the check for buffer overruns BB */
2985 name_len = strnlen(searchName, PATH_MAX);
2986 name_len++; /* trailing null */
2987 strncpy(pSMB->FileName, searchName, name_len);
2988 }
2989
2990 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2991 pSMB->TotalDataCount = 0;
2992 pSMB->MaxParameterCount = cpu_to_le16(2);
2993 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2994 pSMB->MaxSetupCount = 0;
2995 pSMB->Reserved = 0;
2996 pSMB->Flags = 0;
2997 pSMB->Timeout = 0;
2998 pSMB->Reserved2 = 0;
2999 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3000 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3001 pSMB->DataCount = 0;
3002 pSMB->DataOffset = 0;
3003 pSMB->SetupCount = 1;
3004 pSMB->Reserved3 = 0;
3005 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3006 byte_count = params + 1 /* pad */ ;
3007 pSMB->TotalParameterCount = cpu_to_le16(params);
3008 pSMB->ParameterCount = pSMB->TotalParameterCount;
3009 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3010 pSMB->Reserved4 = 0;
3011 pSMB->hdr.smb_buf_length += byte_count;
3012 pSMB->ByteCount = cpu_to_le16(byte_count);
3013
3014 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3015 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3016 if (rc) {
3017 cFYI(1, ("Send error in QPathInfo = %d", rc));
3018 } else { /* decode response */
3019 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3020
3021 if (rc || (pSMBr->ByteCount < 40))
3022 rc = -EIO; /* bad smb */
3023 else if (pFindData){
3024 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3025 memcpy((char *) pFindData,
3026 (char *) &pSMBr->hdr.Protocol +
3027 data_offset, sizeof (FILE_ALL_INFO));
3028 } else
3029 rc = -ENOMEM;
3030 }
3031 cifs_buf_release(pSMB);
3032 if (rc == -EAGAIN)
3033 goto QPathInfoRetry;
3034
3035 return rc;
3036}
3037
3038int
3039CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3040 const unsigned char *searchName,
3041 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003042 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043{
3044/* SMB_QUERY_FILE_UNIX_BASIC */
3045 TRANSACTION2_QPI_REQ *pSMB = NULL;
3046 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3047 int rc = 0;
3048 int bytes_returned = 0;
3049 int name_len;
3050 __u16 params, byte_count;
3051
3052 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3053UnixQPathInfoRetry:
3054 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3055 (void **) &pSMBr);
3056 if (rc)
3057 return rc;
3058
3059 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3060 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003061 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003062 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 name_len++; /* trailing null */
3064 name_len *= 2;
3065 } else { /* BB improve the check for buffer overruns BB */
3066 name_len = strnlen(searchName, PATH_MAX);
3067 name_len++; /* trailing null */
3068 strncpy(pSMB->FileName, searchName, name_len);
3069 }
3070
3071 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3072 pSMB->TotalDataCount = 0;
3073 pSMB->MaxParameterCount = cpu_to_le16(2);
3074 /* BB find exact max SMB PDU from sess structure BB */
3075 pSMB->MaxDataCount = cpu_to_le16(4000);
3076 pSMB->MaxSetupCount = 0;
3077 pSMB->Reserved = 0;
3078 pSMB->Flags = 0;
3079 pSMB->Timeout = 0;
3080 pSMB->Reserved2 = 0;
3081 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3082 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3083 pSMB->DataCount = 0;
3084 pSMB->DataOffset = 0;
3085 pSMB->SetupCount = 1;
3086 pSMB->Reserved3 = 0;
3087 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3088 byte_count = params + 1 /* pad */ ;
3089 pSMB->TotalParameterCount = cpu_to_le16(params);
3090 pSMB->ParameterCount = pSMB->TotalParameterCount;
3091 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3092 pSMB->Reserved4 = 0;
3093 pSMB->hdr.smb_buf_length += byte_count;
3094 pSMB->ByteCount = cpu_to_le16(byte_count);
3095
3096 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3097 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3098 if (rc) {
3099 cFYI(1, ("Send error in QPathInfo = %d", rc));
3100 } else { /* decode response */
3101 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3102
3103 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3104 rc = -EIO; /* bad smb */
3105 } else {
3106 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3107 memcpy((char *) pFindData,
3108 (char *) &pSMBr->hdr.Protocol +
3109 data_offset,
3110 sizeof (FILE_UNIX_BASIC_INFO));
3111 }
3112 }
3113 cifs_buf_release(pSMB);
3114 if (rc == -EAGAIN)
3115 goto UnixQPathInfoRetry;
3116
3117 return rc;
3118}
3119
3120#if 0 /* function unused at present */
3121int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3122 const char *searchName, FILE_ALL_INFO * findData,
3123 const struct nls_table *nls_codepage)
3124{
3125/* level 257 SMB_ */
3126 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3127 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3128 int rc = 0;
3129 int bytes_returned;
3130 int name_len;
3131 __u16 params, byte_count;
3132
3133 cFYI(1, ("In FindUnique"));
3134findUniqueRetry:
3135 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3136 (void **) &pSMBr);
3137 if (rc)
3138 return rc;
3139
3140 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3141 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003142 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 /* find define for this maxpathcomponent */
3144 , nls_codepage);
3145 name_len++; /* trailing null */
3146 name_len *= 2;
3147 } else { /* BB improve the check for buffer overruns BB */
3148 name_len = strnlen(searchName, PATH_MAX);
3149 name_len++; /* trailing null */
3150 strncpy(pSMB->FileName, searchName, name_len);
3151 }
3152
3153 params = 12 + name_len /* includes null */ ;
3154 pSMB->TotalDataCount = 0; /* no EAs */
3155 pSMB->MaxParameterCount = cpu_to_le16(2);
3156 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3157 pSMB->MaxSetupCount = 0;
3158 pSMB->Reserved = 0;
3159 pSMB->Flags = 0;
3160 pSMB->Timeout = 0;
3161 pSMB->Reserved2 = 0;
3162 pSMB->ParameterOffset = cpu_to_le16(
3163 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3164 pSMB->DataCount = 0;
3165 pSMB->DataOffset = 0;
3166 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3167 pSMB->Reserved3 = 0;
3168 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3169 byte_count = params + 1 /* pad */ ;
3170 pSMB->TotalParameterCount = cpu_to_le16(params);
3171 pSMB->ParameterCount = pSMB->TotalParameterCount;
3172 pSMB->SearchAttributes =
3173 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3174 ATTR_DIRECTORY);
3175 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3176 pSMB->SearchFlags = cpu_to_le16(1);
3177 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3178 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3179 pSMB->hdr.smb_buf_length += byte_count;
3180 pSMB->ByteCount = cpu_to_le16(byte_count);
3181
3182 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3183 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3184
3185 if (rc) {
3186 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3187 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003188 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 /* BB fill in */
3190 }
3191
3192 cifs_buf_release(pSMB);
3193 if (rc == -EAGAIN)
3194 goto findUniqueRetry;
3195
3196 return rc;
3197}
3198#endif /* end unused (temporarily) function */
3199
3200/* xid, tcon, searchName and codepage are input parms, rest are returned */
3201int
3202CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3203 const char *searchName,
3204 const struct nls_table *nls_codepage,
3205 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003206 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207{
3208/* level 257 SMB_ */
3209 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3210 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3211 T2_FFIRST_RSP_PARMS * parms;
3212 int rc = 0;
3213 int bytes_returned = 0;
3214 int name_len;
3215 __u16 params, byte_count;
3216
Steve French737b7582005-04-28 22:41:06 -07003217 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218
3219findFirstRetry:
3220 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3221 (void **) &pSMBr);
3222 if (rc)
3223 return rc;
3224
3225 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3226 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003227 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003228 PATH_MAX, nls_codepage, remap);
3229 /* We can not add the asterik earlier in case
3230 it got remapped to 0xF03A as if it were part of the
3231 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003233 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003234 pSMB->FileName[name_len+1] = 0;
3235 pSMB->FileName[name_len+2] = '*';
3236 pSMB->FileName[name_len+3] = 0;
3237 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3239 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003240 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 } else { /* BB add check for overrun of SMB buf BB */
3242 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243/* BB fix here and in unicode clause above ie
3244 if(name_len > buffersize-header)
3245 free buffer exit; BB */
3246 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003247 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003248 pSMB->FileName[name_len+1] = '*';
3249 pSMB->FileName[name_len+2] = 0;
3250 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 }
3252
3253 params = 12 + name_len /* includes null */ ;
3254 pSMB->TotalDataCount = 0; /* no EAs */
3255 pSMB->MaxParameterCount = cpu_to_le16(10);
3256 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3257 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3258 pSMB->MaxSetupCount = 0;
3259 pSMB->Reserved = 0;
3260 pSMB->Flags = 0;
3261 pSMB->Timeout = 0;
3262 pSMB->Reserved2 = 0;
3263 byte_count = params + 1 /* pad */ ;
3264 pSMB->TotalParameterCount = cpu_to_le16(params);
3265 pSMB->ParameterCount = pSMB->TotalParameterCount;
3266 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003267 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3268 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 pSMB->DataCount = 0;
3270 pSMB->DataOffset = 0;
3271 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3272 pSMB->Reserved3 = 0;
3273 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3274 pSMB->SearchAttributes =
3275 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3276 ATTR_DIRECTORY);
3277 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3278 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3279 CIFS_SEARCH_RETURN_RESUME);
3280 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3281
3282 /* BB what should we set StorageType to? Does it matter? BB */
3283 pSMB->SearchStorageType = 0;
3284 pSMB->hdr.smb_buf_length += byte_count;
3285 pSMB->ByteCount = cpu_to_le16(byte_count);
3286
3287 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3288 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003289 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290
Steve French88274812006-03-09 22:21:45 +00003291 if (rc) {/* BB add logic to retry regular search if Unix search
3292 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 /* BB Add code to handle unsupported level rc */
3294 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003295
Steve French88274812006-03-09 22:21:45 +00003296 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297
3298 /* BB eventually could optimize out free and realloc of buf */
3299 /* for this case */
3300 if (rc == -EAGAIN)
3301 goto findFirstRetry;
3302 } else { /* decode response */
3303 /* BB remember to free buffer if error BB */
3304 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3305 if(rc == 0) {
3306 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3307 psrch_inf->unicode = TRUE;
3308 else
3309 psrch_inf->unicode = FALSE;
3310
3311 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003312 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 psrch_inf->srch_entries_start =
3314 (char *) &pSMBr->hdr.Protocol +
3315 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3317 le16_to_cpu(pSMBr->t2.ParameterOffset));
3318
3319 if(parms->EndofSearch)
3320 psrch_inf->endOfSearch = TRUE;
3321 else
3322 psrch_inf->endOfSearch = FALSE;
3323
3324 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003325 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 *pnetfid = parms->SearchHandle;
3328 } else {
3329 cifs_buf_release(pSMB);
3330 }
3331 }
3332
3333 return rc;
3334}
3335
3336int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3337 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3338{
3339 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3340 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3341 T2_FNEXT_RSP_PARMS * parms;
3342 char *response_data;
3343 int rc = 0;
3344 int bytes_returned, name_len;
3345 __u16 params, byte_count;
3346
3347 cFYI(1, ("In FindNext"));
3348
3349 if(psrch_inf->endOfSearch == TRUE)
3350 return -ENOENT;
3351
3352 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3353 (void **) &pSMBr);
3354 if (rc)
3355 return rc;
3356
3357 params = 14; /* includes 2 bytes of null string, converted to LE below */
3358 byte_count = 0;
3359 pSMB->TotalDataCount = 0; /* no EAs */
3360 pSMB->MaxParameterCount = cpu_to_le16(8);
3361 pSMB->MaxDataCount =
3362 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3363 pSMB->MaxSetupCount = 0;
3364 pSMB->Reserved = 0;
3365 pSMB->Flags = 0;
3366 pSMB->Timeout = 0;
3367 pSMB->Reserved2 = 0;
3368 pSMB->ParameterOffset = cpu_to_le16(
3369 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3370 pSMB->DataCount = 0;
3371 pSMB->DataOffset = 0;
3372 pSMB->SetupCount = 1;
3373 pSMB->Reserved3 = 0;
3374 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3375 pSMB->SearchHandle = searchHandle; /* always kept as le */
3376 pSMB->SearchCount =
3377 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3378 /* test for Unix extensions */
3379/* if (tcon->ses->capabilities & CAP_UNIX) {
3380 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3381 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3382 } else {
3383 pSMB->InformationLevel =
3384 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3385 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3386 } */
3387 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3388 pSMB->ResumeKey = psrch_inf->resume_key;
3389 pSMB->SearchFlags =
3390 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3391
3392 name_len = psrch_inf->resume_name_len;
3393 params += name_len;
3394 if(name_len < PATH_MAX) {
3395 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3396 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003397 /* 14 byte parm len above enough for 2 byte null terminator */
3398 pSMB->ResumeFileName[name_len] = 0;
3399 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 } else {
3401 rc = -EINVAL;
3402 goto FNext2_err_exit;
3403 }
3404 byte_count = params + 1 /* pad */ ;
3405 pSMB->TotalParameterCount = cpu_to_le16(params);
3406 pSMB->ParameterCount = pSMB->TotalParameterCount;
3407 pSMB->hdr.smb_buf_length += byte_count;
3408 pSMB->ByteCount = cpu_to_le16(byte_count);
3409
3410 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3411 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003412 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 if (rc) {
3414 if (rc == -EBADF) {
3415 psrch_inf->endOfSearch = TRUE;
3416 rc = 0; /* search probably was closed at end of search above */
3417 } else
3418 cFYI(1, ("FindNext returned = %d", rc));
3419 } else { /* decode response */
3420 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3421
3422 if(rc == 0) {
3423 /* BB fixme add lock for file (srch_info) struct here */
3424 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3425 psrch_inf->unicode = TRUE;
3426 else
3427 psrch_inf->unicode = FALSE;
3428 response_data = (char *) &pSMBr->hdr.Protocol +
3429 le16_to_cpu(pSMBr->t2.ParameterOffset);
3430 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3431 response_data = (char *)&pSMBr->hdr.Protocol +
3432 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003433 if(psrch_inf->smallBuf)
3434 cifs_small_buf_release(
3435 psrch_inf->ntwrk_buf_start);
3436 else
3437 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 psrch_inf->srch_entries_start = response_data;
3439 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003440 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 if(parms->EndofSearch)
3442 psrch_inf->endOfSearch = TRUE;
3443 else
3444 psrch_inf->endOfSearch = FALSE;
3445
3446 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3447 psrch_inf->index_of_last_entry +=
3448 psrch_inf->entries_in_buffer;
3449/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3450
3451 /* BB fixme add unlock here */
3452 }
3453
3454 }
3455
3456 /* BB On error, should we leave previous search buf (and count and
3457 last entry fields) intact or free the previous one? */
3458
3459 /* Note: On -EAGAIN error only caller can retry on handle based calls
3460 since file handle passed in no longer valid */
3461FNext2_err_exit:
3462 if (rc != 0)
3463 cifs_buf_release(pSMB);
3464
3465 return rc;
3466}
3467
3468int
3469CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3470{
3471 int rc = 0;
3472 FINDCLOSE_REQ *pSMB = NULL;
3473 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3474 int bytes_returned;
3475
3476 cFYI(1, ("In CIFSSMBFindClose"));
3477 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3478
3479 /* no sense returning error if session restarted
3480 as file handle has been closed */
3481 if(rc == -EAGAIN)
3482 return 0;
3483 if (rc)
3484 return rc;
3485
3486 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3487 pSMB->FileID = searchHandle;
3488 pSMB->ByteCount = 0;
3489 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3490 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3491 if (rc) {
3492 cERROR(1, ("Send error in FindClose = %d", rc));
3493 }
Steve Frencha4544342005-08-24 13:59:35 -07003494 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 cifs_small_buf_release(pSMB);
3496
3497 /* Since session is dead, search handle closed on server already */
3498 if (rc == -EAGAIN)
3499 rc = 0;
3500
3501 return rc;
3502}
3503
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504int
3505CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3506 const unsigned char *searchName,
3507 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003508 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509{
3510 int rc = 0;
3511 TRANSACTION2_QPI_REQ *pSMB = NULL;
3512 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3513 int name_len, bytes_returned;
3514 __u16 params, byte_count;
3515
3516 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3517 if(tcon == NULL)
3518 return -ENODEV;
3519
3520GetInodeNumberRetry:
3521 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3522 (void **) &pSMBr);
3523 if (rc)
3524 return rc;
3525
3526
3527 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3528 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003529 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003530 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 name_len++; /* trailing null */
3532 name_len *= 2;
3533 } else { /* BB improve the check for buffer overruns BB */
3534 name_len = strnlen(searchName, PATH_MAX);
3535 name_len++; /* trailing null */
3536 strncpy(pSMB->FileName, searchName, name_len);
3537 }
3538
3539 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3540 pSMB->TotalDataCount = 0;
3541 pSMB->MaxParameterCount = cpu_to_le16(2);
3542 /* BB find exact max data count below from sess structure BB */
3543 pSMB->MaxDataCount = cpu_to_le16(4000);
3544 pSMB->MaxSetupCount = 0;
3545 pSMB->Reserved = 0;
3546 pSMB->Flags = 0;
3547 pSMB->Timeout = 0;
3548 pSMB->Reserved2 = 0;
3549 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3550 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3551 pSMB->DataCount = 0;
3552 pSMB->DataOffset = 0;
3553 pSMB->SetupCount = 1;
3554 pSMB->Reserved3 = 0;
3555 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3556 byte_count = params + 1 /* pad */ ;
3557 pSMB->TotalParameterCount = cpu_to_le16(params);
3558 pSMB->ParameterCount = pSMB->TotalParameterCount;
3559 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3560 pSMB->Reserved4 = 0;
3561 pSMB->hdr.smb_buf_length += byte_count;
3562 pSMB->ByteCount = cpu_to_le16(byte_count);
3563
3564 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3565 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3566 if (rc) {
3567 cFYI(1, ("error %d in QueryInternalInfo", rc));
3568 } else {
3569 /* decode response */
3570 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3571 if (rc || (pSMBr->ByteCount < 2))
3572 /* BB also check enough total bytes returned */
3573 /* If rc should we check for EOPNOSUPP and
3574 disable the srvino flag? or in caller? */
3575 rc = -EIO; /* bad smb */
3576 else {
3577 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3578 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3579 struct file_internal_info * pfinfo;
3580 /* BB Do we need a cast or hash here ? */
3581 if(count < 8) {
3582 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3583 rc = -EIO;
3584 goto GetInodeNumOut;
3585 }
3586 pfinfo = (struct file_internal_info *)
3587 (data_offset + (char *) &pSMBr->hdr.Protocol);
3588 *inode_number = pfinfo->UniqueId;
3589 }
3590 }
3591GetInodeNumOut:
3592 cifs_buf_release(pSMB);
3593 if (rc == -EAGAIN)
3594 goto GetInodeNumberRetry;
3595 return rc;
3596}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597
3598int
3599CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3600 const unsigned char *searchName,
3601 unsigned char **targetUNCs,
3602 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003603 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604{
3605/* TRANS2_GET_DFS_REFERRAL */
3606 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3607 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3608 struct dfs_referral_level_3 * referrals = NULL;
3609 int rc = 0;
3610 int bytes_returned;
3611 int name_len;
3612 unsigned int i;
3613 char * temp;
3614 __u16 params, byte_count;
3615 *number_of_UNC_in_array = 0;
3616 *targetUNCs = NULL;
3617
3618 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3619 if (ses == NULL)
3620 return -ENODEV;
3621getDFSRetry:
3622 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3623 (void **) &pSMBr);
3624 if (rc)
3625 return rc;
Steve French1982c342005-08-17 12:38:22 -07003626
3627 /* server pointer checked in called function,
3628 but should never be null here anyway */
3629 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 pSMB->hdr.Tid = ses->ipc_tid;
3631 pSMB->hdr.Uid = ses->Suid;
3632 if (ses->capabilities & CAP_STATUS32) {
3633 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3634 }
3635 if (ses->capabilities & CAP_DFS) {
3636 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3637 }
3638
3639 if (ses->capabilities & CAP_UNICODE) {
3640 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3641 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003642 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003643 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 name_len++; /* trailing null */
3645 name_len *= 2;
3646 } else { /* BB improve the check for buffer overruns BB */
3647 name_len = strnlen(searchName, PATH_MAX);
3648 name_len++; /* trailing null */
3649 strncpy(pSMB->RequestFileName, searchName, name_len);
3650 }
3651
3652 params = 2 /* level */ + name_len /*includes null */ ;
3653 pSMB->TotalDataCount = 0;
3654 pSMB->DataCount = 0;
3655 pSMB->DataOffset = 0;
3656 pSMB->MaxParameterCount = 0;
3657 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3658 pSMB->MaxSetupCount = 0;
3659 pSMB->Reserved = 0;
3660 pSMB->Flags = 0;
3661 pSMB->Timeout = 0;
3662 pSMB->Reserved2 = 0;
3663 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3664 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3665 pSMB->SetupCount = 1;
3666 pSMB->Reserved3 = 0;
3667 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3668 byte_count = params + 3 /* pad */ ;
3669 pSMB->ParameterCount = cpu_to_le16(params);
3670 pSMB->TotalParameterCount = pSMB->ParameterCount;
3671 pSMB->MaxReferralLevel = cpu_to_le16(3);
3672 pSMB->hdr.smb_buf_length += byte_count;
3673 pSMB->ByteCount = cpu_to_le16(byte_count);
3674
3675 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3676 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3677 if (rc) {
3678 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3679 } else { /* decode response */
3680/* BB Add logic to parse referrals here */
3681 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3682
3683 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3684 rc = -EIO; /* bad smb */
3685 else {
3686 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3687 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3688
3689 cFYI(1,
3690 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3691 pSMBr->ByteCount, data_offset));
3692 referrals =
3693 (struct dfs_referral_level_3 *)
3694 (8 /* sizeof start of data block */ +
3695 data_offset +
3696 (char *) &pSMBr->hdr.Protocol);
3697 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",
3698 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)));
3699 /* BB This field is actually two bytes in from start of
3700 data block so we could do safety check that DataBlock
3701 begins at address of pSMBr->NumberOfReferrals */
3702 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3703
3704 /* BB Fix below so can return more than one referral */
3705 if(*number_of_UNC_in_array > 1)
3706 *number_of_UNC_in_array = 1;
3707
3708 /* get the length of the strings describing refs */
3709 name_len = 0;
3710 for(i=0;i<*number_of_UNC_in_array;i++) {
3711 /* make sure that DfsPathOffset not past end */
3712 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3713 if (offset > data_count) {
3714 /* if invalid referral, stop here and do
3715 not try to copy any more */
3716 *number_of_UNC_in_array = i;
3717 break;
3718 }
3719 temp = ((char *)referrals) + offset;
3720
3721 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3722 name_len += UniStrnlen((wchar_t *)temp,data_count);
3723 } else {
3724 name_len += strnlen(temp,data_count);
3725 }
3726 referrals++;
3727 /* BB add check that referral pointer does not fall off end PDU */
3728
3729 }
3730 /* BB add check for name_len bigger than bcc */
3731 *targetUNCs =
3732 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3733 if(*targetUNCs == NULL) {
3734 rc = -ENOMEM;
3735 goto GetDFSRefExit;
3736 }
3737 /* copy the ref strings */
3738 referrals =
3739 (struct dfs_referral_level_3 *)
3740 (8 /* sizeof data hdr */ +
3741 data_offset +
3742 (char *) &pSMBr->hdr.Protocol);
3743
3744 for(i=0;i<*number_of_UNC_in_array;i++) {
3745 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3746 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3747 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003748 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 } else {
3750 strncpy(*targetUNCs,temp,name_len);
3751 }
3752 /* BB update target_uncs pointers */
3753 referrals++;
3754 }
3755 temp = *targetUNCs;
3756 temp[name_len] = 0;
3757 }
3758
3759 }
3760GetDFSRefExit:
3761 if (pSMB)
3762 cifs_buf_release(pSMB);
3763
3764 if (rc == -EAGAIN)
3765 goto getDFSRetry;
3766
3767 return rc;
3768}
3769
Steve French20962432005-09-21 22:05:57 -07003770/* Query File System Info such as free space to old servers such as Win 9x */
3771int
3772SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3773{
3774/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3775 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3776 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3777 FILE_SYSTEM_ALLOC_INFO *response_data;
3778 int rc = 0;
3779 int bytes_returned = 0;
3780 __u16 params, byte_count;
3781
3782 cFYI(1, ("OldQFSInfo"));
3783oldQFSInfoRetry:
3784 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3785 (void **) &pSMBr);
3786 if (rc)
3787 return rc;
3788 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3789 (void **) &pSMBr);
3790 if (rc)
3791 return rc;
3792
3793 params = 2; /* level */
3794 pSMB->TotalDataCount = 0;
3795 pSMB->MaxParameterCount = cpu_to_le16(2);
3796 pSMB->MaxDataCount = cpu_to_le16(1000);
3797 pSMB->MaxSetupCount = 0;
3798 pSMB->Reserved = 0;
3799 pSMB->Flags = 0;
3800 pSMB->Timeout = 0;
3801 pSMB->Reserved2 = 0;
3802 byte_count = params + 1 /* pad */ ;
3803 pSMB->TotalParameterCount = cpu_to_le16(params);
3804 pSMB->ParameterCount = pSMB->TotalParameterCount;
3805 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3806 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3807 pSMB->DataCount = 0;
3808 pSMB->DataOffset = 0;
3809 pSMB->SetupCount = 1;
3810 pSMB->Reserved3 = 0;
3811 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3812 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3813 pSMB->hdr.smb_buf_length += byte_count;
3814 pSMB->ByteCount = cpu_to_le16(byte_count);
3815
3816 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3817 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3818 if (rc) {
3819 cFYI(1, ("Send error in QFSInfo = %d", rc));
3820 } else { /* decode response */
3821 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3822
3823 if (rc || (pSMBr->ByteCount < 18))
3824 rc = -EIO; /* bad smb */
3825 else {
3826 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3827 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3828 pSMBr->ByteCount, data_offset));
3829
3830 response_data =
3831 (FILE_SYSTEM_ALLOC_INFO *)
3832 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3833 FSData->f_bsize =
3834 le16_to_cpu(response_data->BytesPerSector) *
3835 le32_to_cpu(response_data->
3836 SectorsPerAllocationUnit);
3837 FSData->f_blocks =
3838 le32_to_cpu(response_data->TotalAllocationUnits);
3839 FSData->f_bfree = FSData->f_bavail =
3840 le32_to_cpu(response_data->FreeAllocationUnits);
3841 cFYI(1,
3842 ("Blocks: %lld Free: %lld Block size %ld",
3843 (unsigned long long)FSData->f_blocks,
3844 (unsigned long long)FSData->f_bfree,
3845 FSData->f_bsize));
3846 }
3847 }
3848 cifs_buf_release(pSMB);
3849
3850 if (rc == -EAGAIN)
3851 goto oldQFSInfoRetry;
3852
3853 return rc;
3854}
3855
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856int
Steve French737b7582005-04-28 22:41:06 -07003857CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858{
3859/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3860 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3861 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3862 FILE_SYSTEM_INFO *response_data;
3863 int rc = 0;
3864 int bytes_returned = 0;
3865 __u16 params, byte_count;
3866
3867 cFYI(1, ("In QFSInfo"));
3868QFSInfoRetry:
3869 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3870 (void **) &pSMBr);
3871 if (rc)
3872 return rc;
3873
3874 params = 2; /* level */
3875 pSMB->TotalDataCount = 0;
3876 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003877 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 pSMB->MaxSetupCount = 0;
3879 pSMB->Reserved = 0;
3880 pSMB->Flags = 0;
3881 pSMB->Timeout = 0;
3882 pSMB->Reserved2 = 0;
3883 byte_count = params + 1 /* pad */ ;
3884 pSMB->TotalParameterCount = cpu_to_le16(params);
3885 pSMB->ParameterCount = pSMB->TotalParameterCount;
3886 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3887 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3888 pSMB->DataCount = 0;
3889 pSMB->DataOffset = 0;
3890 pSMB->SetupCount = 1;
3891 pSMB->Reserved3 = 0;
3892 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3893 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3894 pSMB->hdr.smb_buf_length += byte_count;
3895 pSMB->ByteCount = cpu_to_le16(byte_count);
3896
3897 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3898 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3899 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003900 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 } else { /* decode response */
3902 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3903
Steve French20962432005-09-21 22:05:57 -07003904 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 rc = -EIO; /* bad smb */
3906 else {
3907 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908
3909 response_data =
3910 (FILE_SYSTEM_INFO
3911 *) (((char *) &pSMBr->hdr.Protocol) +
3912 data_offset);
3913 FSData->f_bsize =
3914 le32_to_cpu(response_data->BytesPerSector) *
3915 le32_to_cpu(response_data->
3916 SectorsPerAllocationUnit);
3917 FSData->f_blocks =
3918 le64_to_cpu(response_data->TotalAllocationUnits);
3919 FSData->f_bfree = FSData->f_bavail =
3920 le64_to_cpu(response_data->FreeAllocationUnits);
3921 cFYI(1,
3922 ("Blocks: %lld Free: %lld Block size %ld",
3923 (unsigned long long)FSData->f_blocks,
3924 (unsigned long long)FSData->f_bfree,
3925 FSData->f_bsize));
3926 }
3927 }
3928 cifs_buf_release(pSMB);
3929
3930 if (rc == -EAGAIN)
3931 goto QFSInfoRetry;
3932
3933 return rc;
3934}
3935
3936int
Steve French737b7582005-04-28 22:41:06 -07003937CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938{
3939/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3940 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3941 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3942 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3943 int rc = 0;
3944 int bytes_returned = 0;
3945 __u16 params, byte_count;
3946
3947 cFYI(1, ("In QFSAttributeInfo"));
3948QFSAttributeRetry:
3949 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3950 (void **) &pSMBr);
3951 if (rc)
3952 return rc;
3953
3954 params = 2; /* level */
3955 pSMB->TotalDataCount = 0;
3956 pSMB->MaxParameterCount = cpu_to_le16(2);
3957 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3958 pSMB->MaxSetupCount = 0;
3959 pSMB->Reserved = 0;
3960 pSMB->Flags = 0;
3961 pSMB->Timeout = 0;
3962 pSMB->Reserved2 = 0;
3963 byte_count = params + 1 /* pad */ ;
3964 pSMB->TotalParameterCount = cpu_to_le16(params);
3965 pSMB->ParameterCount = pSMB->TotalParameterCount;
3966 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3967 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3968 pSMB->DataCount = 0;
3969 pSMB->DataOffset = 0;
3970 pSMB->SetupCount = 1;
3971 pSMB->Reserved3 = 0;
3972 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3973 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3974 pSMB->hdr.smb_buf_length += byte_count;
3975 pSMB->ByteCount = cpu_to_le16(byte_count);
3976
3977 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3978 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3979 if (rc) {
3980 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3981 } else { /* decode response */
3982 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3983
3984 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3985 rc = -EIO; /* bad smb */
3986 } else {
3987 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3988 response_data =
3989 (FILE_SYSTEM_ATTRIBUTE_INFO
3990 *) (((char *) &pSMBr->hdr.Protocol) +
3991 data_offset);
3992 memcpy(&tcon->fsAttrInfo, response_data,
3993 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3994 }
3995 }
3996 cifs_buf_release(pSMB);
3997
3998 if (rc == -EAGAIN)
3999 goto QFSAttributeRetry;
4000
4001 return rc;
4002}
4003
4004int
Steve French737b7582005-04-28 22:41:06 -07004005CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006{
4007/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4008 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4009 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4010 FILE_SYSTEM_DEVICE_INFO *response_data;
4011 int rc = 0;
4012 int bytes_returned = 0;
4013 __u16 params, byte_count;
4014
4015 cFYI(1, ("In QFSDeviceInfo"));
4016QFSDeviceRetry:
4017 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4018 (void **) &pSMBr);
4019 if (rc)
4020 return rc;
4021
4022 params = 2; /* level */
4023 pSMB->TotalDataCount = 0;
4024 pSMB->MaxParameterCount = cpu_to_le16(2);
4025 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4026 pSMB->MaxSetupCount = 0;
4027 pSMB->Reserved = 0;
4028 pSMB->Flags = 0;
4029 pSMB->Timeout = 0;
4030 pSMB->Reserved2 = 0;
4031 byte_count = params + 1 /* pad */ ;
4032 pSMB->TotalParameterCount = cpu_to_le16(params);
4033 pSMB->ParameterCount = pSMB->TotalParameterCount;
4034 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4035 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4036
4037 pSMB->DataCount = 0;
4038 pSMB->DataOffset = 0;
4039 pSMB->SetupCount = 1;
4040 pSMB->Reserved3 = 0;
4041 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4042 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4043 pSMB->hdr.smb_buf_length += byte_count;
4044 pSMB->ByteCount = cpu_to_le16(byte_count);
4045
4046 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4047 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4048 if (rc) {
4049 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4050 } else { /* decode response */
4051 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4052
4053 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4054 rc = -EIO; /* bad smb */
4055 else {
4056 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4057 response_data =
Steve French737b7582005-04-28 22:41:06 -07004058 (FILE_SYSTEM_DEVICE_INFO *)
4059 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 data_offset);
4061 memcpy(&tcon->fsDevInfo, response_data,
4062 sizeof (FILE_SYSTEM_DEVICE_INFO));
4063 }
4064 }
4065 cifs_buf_release(pSMB);
4066
4067 if (rc == -EAGAIN)
4068 goto QFSDeviceRetry;
4069
4070 return rc;
4071}
4072
4073int
Steve French737b7582005-04-28 22:41:06 -07004074CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075{
4076/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4077 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4078 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4079 FILE_SYSTEM_UNIX_INFO *response_data;
4080 int rc = 0;
4081 int bytes_returned = 0;
4082 __u16 params, byte_count;
4083
4084 cFYI(1, ("In QFSUnixInfo"));
4085QFSUnixRetry:
4086 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4087 (void **) &pSMBr);
4088 if (rc)
4089 return rc;
4090
4091 params = 2; /* level */
4092 pSMB->TotalDataCount = 0;
4093 pSMB->DataCount = 0;
4094 pSMB->DataOffset = 0;
4095 pSMB->MaxParameterCount = cpu_to_le16(2);
4096 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4097 pSMB->MaxSetupCount = 0;
4098 pSMB->Reserved = 0;
4099 pSMB->Flags = 0;
4100 pSMB->Timeout = 0;
4101 pSMB->Reserved2 = 0;
4102 byte_count = params + 1 /* pad */ ;
4103 pSMB->ParameterCount = cpu_to_le16(params);
4104 pSMB->TotalParameterCount = pSMB->ParameterCount;
4105 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4106 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4107 pSMB->SetupCount = 1;
4108 pSMB->Reserved3 = 0;
4109 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4110 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4111 pSMB->hdr.smb_buf_length += byte_count;
4112 pSMB->ByteCount = cpu_to_le16(byte_count);
4113
4114 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4115 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4116 if (rc) {
4117 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4118 } else { /* decode response */
4119 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4120
4121 if (rc || (pSMBr->ByteCount < 13)) {
4122 rc = -EIO; /* bad smb */
4123 } else {
4124 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4125 response_data =
4126 (FILE_SYSTEM_UNIX_INFO
4127 *) (((char *) &pSMBr->hdr.Protocol) +
4128 data_offset);
4129 memcpy(&tcon->fsUnixInfo, response_data,
4130 sizeof (FILE_SYSTEM_UNIX_INFO));
4131 }
4132 }
4133 cifs_buf_release(pSMB);
4134
4135 if (rc == -EAGAIN)
4136 goto QFSUnixRetry;
4137
4138
4139 return rc;
4140}
4141
Jeremy Allisonac670552005-06-22 17:26:35 -07004142int
Steve French45abc6e2005-06-23 13:42:03 -05004143CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004144{
4145/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4146 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4147 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4148 int rc = 0;
4149 int bytes_returned = 0;
4150 __u16 params, param_offset, offset, byte_count;
4151
4152 cFYI(1, ("In SETFSUnixInfo"));
4153SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004154 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004155 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4156 (void **) &pSMBr);
4157 if (rc)
4158 return rc;
4159
4160 params = 4; /* 2 bytes zero followed by info level. */
4161 pSMB->MaxSetupCount = 0;
4162 pSMB->Reserved = 0;
4163 pSMB->Flags = 0;
4164 pSMB->Timeout = 0;
4165 pSMB->Reserved2 = 0;
4166 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4167 offset = param_offset + params;
4168
4169 pSMB->MaxParameterCount = cpu_to_le16(4);
4170 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4171 pSMB->SetupCount = 1;
4172 pSMB->Reserved3 = 0;
4173 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4174 byte_count = 1 /* pad */ + params + 12;
4175
4176 pSMB->DataCount = cpu_to_le16(12);
4177 pSMB->ParameterCount = cpu_to_le16(params);
4178 pSMB->TotalDataCount = pSMB->DataCount;
4179 pSMB->TotalParameterCount = pSMB->ParameterCount;
4180 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4181 pSMB->DataOffset = cpu_to_le16(offset);
4182
4183 /* Params. */
4184 pSMB->FileNum = 0;
4185 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4186
4187 /* Data. */
4188 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4189 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4190 pSMB->ClientUnixCap = cpu_to_le64(cap);
4191
4192 pSMB->hdr.smb_buf_length += byte_count;
4193 pSMB->ByteCount = cpu_to_le16(byte_count);
4194
4195 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4196 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4197 if (rc) {
4198 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4199 } else { /* decode response */
4200 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4201 if (rc) {
4202 rc = -EIO; /* bad smb */
4203 }
4204 }
4205 cifs_buf_release(pSMB);
4206
4207 if (rc == -EAGAIN)
4208 goto SETFSUnixRetry;
4209
4210 return rc;
4211}
4212
4213
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214
4215int
4216CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004217 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218{
4219/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4220 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4221 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4222 FILE_SYSTEM_POSIX_INFO *response_data;
4223 int rc = 0;
4224 int bytes_returned = 0;
4225 __u16 params, byte_count;
4226
4227 cFYI(1, ("In QFSPosixInfo"));
4228QFSPosixRetry:
4229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4230 (void **) &pSMBr);
4231 if (rc)
4232 return rc;
4233
4234 params = 2; /* level */
4235 pSMB->TotalDataCount = 0;
4236 pSMB->DataCount = 0;
4237 pSMB->DataOffset = 0;
4238 pSMB->MaxParameterCount = cpu_to_le16(2);
4239 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4240 pSMB->MaxSetupCount = 0;
4241 pSMB->Reserved = 0;
4242 pSMB->Flags = 0;
4243 pSMB->Timeout = 0;
4244 pSMB->Reserved2 = 0;
4245 byte_count = params + 1 /* pad */ ;
4246 pSMB->ParameterCount = cpu_to_le16(params);
4247 pSMB->TotalParameterCount = pSMB->ParameterCount;
4248 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4249 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4250 pSMB->SetupCount = 1;
4251 pSMB->Reserved3 = 0;
4252 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4253 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4254 pSMB->hdr.smb_buf_length += byte_count;
4255 pSMB->ByteCount = cpu_to_le16(byte_count);
4256
4257 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4258 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4259 if (rc) {
4260 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4261 } else { /* decode response */
4262 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4263
4264 if (rc || (pSMBr->ByteCount < 13)) {
4265 rc = -EIO; /* bad smb */
4266 } else {
4267 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4268 response_data =
4269 (FILE_SYSTEM_POSIX_INFO
4270 *) (((char *) &pSMBr->hdr.Protocol) +
4271 data_offset);
4272 FSData->f_bsize =
4273 le32_to_cpu(response_data->BlockSize);
4274 FSData->f_blocks =
4275 le64_to_cpu(response_data->TotalBlocks);
4276 FSData->f_bfree =
4277 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004278 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 FSData->f_bavail = FSData->f_bfree;
4280 } else {
4281 FSData->f_bavail =
4282 le64_to_cpu(response_data->UserBlocksAvail);
4283 }
Steve French70ca7342005-09-22 16:32:06 -07004284 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 FSData->f_files =
4286 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004287 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 FSData->f_ffree =
4289 le64_to_cpu(response_data->FreeFileNodes);
4290 }
4291 }
4292 cifs_buf_release(pSMB);
4293
4294 if (rc == -EAGAIN)
4295 goto QFSPosixRetry;
4296
4297 return rc;
4298}
4299
4300
4301/* We can not use write of zero bytes trick to
4302 set file size due to need for large file support. Also note that
4303 this SetPathInfo is preferred to SetFileInfo based method in next
4304 routine which is only needed to work around a sharing violation bug
4305 in Samba which this routine can run into */
4306
4307int
4308CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004309 __u64 size, int SetAllocation,
4310 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311{
4312 struct smb_com_transaction2_spi_req *pSMB = NULL;
4313 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4314 struct file_end_of_file_info *parm_data;
4315 int name_len;
4316 int rc = 0;
4317 int bytes_returned = 0;
4318 __u16 params, byte_count, data_count, param_offset, offset;
4319
4320 cFYI(1, ("In SetEOF"));
4321SetEOFRetry:
4322 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4323 (void **) &pSMBr);
4324 if (rc)
4325 return rc;
4326
4327 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4328 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004329 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004330 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 name_len++; /* trailing null */
4332 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004333 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 name_len = strnlen(fileName, PATH_MAX);
4335 name_len++; /* trailing null */
4336 strncpy(pSMB->FileName, fileName, name_len);
4337 }
4338 params = 6 + name_len;
4339 data_count = sizeof (struct file_end_of_file_info);
4340 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004341 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 pSMB->MaxSetupCount = 0;
4343 pSMB->Reserved = 0;
4344 pSMB->Flags = 0;
4345 pSMB->Timeout = 0;
4346 pSMB->Reserved2 = 0;
4347 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4348 InformationLevel) - 4;
4349 offset = param_offset + params;
4350 if(SetAllocation) {
4351 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4352 pSMB->InformationLevel =
4353 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4354 else
4355 pSMB->InformationLevel =
4356 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4357 } else /* Set File Size */ {
4358 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4359 pSMB->InformationLevel =
4360 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4361 else
4362 pSMB->InformationLevel =
4363 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4364 }
4365
4366 parm_data =
4367 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4368 offset);
4369 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4370 pSMB->DataOffset = cpu_to_le16(offset);
4371 pSMB->SetupCount = 1;
4372 pSMB->Reserved3 = 0;
4373 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4374 byte_count = 3 /* pad */ + params + data_count;
4375 pSMB->DataCount = cpu_to_le16(data_count);
4376 pSMB->TotalDataCount = pSMB->DataCount;
4377 pSMB->ParameterCount = cpu_to_le16(params);
4378 pSMB->TotalParameterCount = pSMB->ParameterCount;
4379 pSMB->Reserved4 = 0;
4380 pSMB->hdr.smb_buf_length += byte_count;
4381 parm_data->FileSize = cpu_to_le64(size);
4382 pSMB->ByteCount = cpu_to_le16(byte_count);
4383 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4384 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4385 if (rc) {
4386 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4387 }
4388
4389 cifs_buf_release(pSMB);
4390
4391 if (rc == -EAGAIN)
4392 goto SetEOFRetry;
4393
4394 return rc;
4395}
4396
4397int
4398CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4399 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4400{
4401 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4402 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4403 char *data_offset;
4404 struct file_end_of_file_info *parm_data;
4405 int rc = 0;
4406 int bytes_returned = 0;
4407 __u16 params, param_offset, offset, byte_count, count;
4408
4409 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4410 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004411 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4412
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 if (rc)
4414 return rc;
4415
Steve Frenchcd634992005-04-28 22:41:10 -07004416 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4417
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4419 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4420
4421 params = 6;
4422 pSMB->MaxSetupCount = 0;
4423 pSMB->Reserved = 0;
4424 pSMB->Flags = 0;
4425 pSMB->Timeout = 0;
4426 pSMB->Reserved2 = 0;
4427 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4428 offset = param_offset + params;
4429
4430 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4431
4432 count = sizeof(struct file_end_of_file_info);
4433 pSMB->MaxParameterCount = cpu_to_le16(2);
4434 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4435 pSMB->SetupCount = 1;
4436 pSMB->Reserved3 = 0;
4437 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4438 byte_count = 3 /* pad */ + params + count;
4439 pSMB->DataCount = cpu_to_le16(count);
4440 pSMB->ParameterCount = cpu_to_le16(params);
4441 pSMB->TotalDataCount = pSMB->DataCount;
4442 pSMB->TotalParameterCount = pSMB->ParameterCount;
4443 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4444 parm_data =
4445 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4446 offset);
4447 pSMB->DataOffset = cpu_to_le16(offset);
4448 parm_data->FileSize = cpu_to_le64(size);
4449 pSMB->Fid = fid;
4450 if(SetAllocation) {
4451 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4452 pSMB->InformationLevel =
4453 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4454 else
4455 pSMB->InformationLevel =
4456 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4457 } else /* Set File Size */ {
4458 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4459 pSMB->InformationLevel =
4460 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4461 else
4462 pSMB->InformationLevel =
4463 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4464 }
4465 pSMB->Reserved4 = 0;
4466 pSMB->hdr.smb_buf_length += byte_count;
4467 pSMB->ByteCount = cpu_to_le16(byte_count);
4468 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4469 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4470 if (rc) {
4471 cFYI(1,
4472 ("Send error in SetFileInfo (SetFileSize) = %d",
4473 rc));
4474 }
4475
4476 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004477 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478
4479 /* Note: On -EAGAIN error only caller can retry on handle based calls
4480 since file handle passed in no longer valid */
4481
4482 return rc;
4483}
4484
4485/* Some legacy servers such as NT4 require that the file times be set on
4486 an open handle, rather than by pathname - this is awkward due to
4487 potential access conflicts on the open, but it is unavoidable for these
4488 old servers since the only other choice is to go from 100 nanosecond DCE
4489 time and resort to the original setpathinfo level which takes the ancient
4490 DOS time format with 2 second granularity */
4491int
4492CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4493 __u16 fid)
4494{
4495 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4496 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4497 char *data_offset;
4498 int rc = 0;
4499 int bytes_returned = 0;
4500 __u16 params, param_offset, offset, byte_count, count;
4501
4502 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004503 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4504
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 if (rc)
4506 return rc;
4507
Steve Frenchcd634992005-04-28 22:41:10 -07004508 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4509
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 /* At this point there is no need to override the current pid
4511 with the pid of the opener, but that could change if we someday
4512 use an existing handle (rather than opening one on the fly) */
4513 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4514 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4515
4516 params = 6;
4517 pSMB->MaxSetupCount = 0;
4518 pSMB->Reserved = 0;
4519 pSMB->Flags = 0;
4520 pSMB->Timeout = 0;
4521 pSMB->Reserved2 = 0;
4522 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4523 offset = param_offset + params;
4524
4525 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4526
4527 count = sizeof (FILE_BASIC_INFO);
4528 pSMB->MaxParameterCount = cpu_to_le16(2);
4529 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4530 pSMB->SetupCount = 1;
4531 pSMB->Reserved3 = 0;
4532 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4533 byte_count = 3 /* pad */ + params + count;
4534 pSMB->DataCount = cpu_to_le16(count);
4535 pSMB->ParameterCount = cpu_to_le16(params);
4536 pSMB->TotalDataCount = pSMB->DataCount;
4537 pSMB->TotalParameterCount = pSMB->ParameterCount;
4538 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4539 pSMB->DataOffset = cpu_to_le16(offset);
4540 pSMB->Fid = fid;
4541 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4542 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4543 else
4544 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4545 pSMB->Reserved4 = 0;
4546 pSMB->hdr.smb_buf_length += byte_count;
4547 pSMB->ByteCount = cpu_to_le16(byte_count);
4548 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4549 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4550 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4551 if (rc) {
4552 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4553 }
4554
Steve Frenchcd634992005-04-28 22:41:10 -07004555 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556
4557 /* Note: On -EAGAIN error only caller can retry on handle based calls
4558 since file handle passed in no longer valid */
4559
4560 return rc;
4561}
4562
4563
4564int
4565CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4566 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004567 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568{
4569 TRANSACTION2_SPI_REQ *pSMB = NULL;
4570 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4571 int name_len;
4572 int rc = 0;
4573 int bytes_returned = 0;
4574 char *data_offset;
4575 __u16 params, param_offset, offset, byte_count, count;
4576
4577 cFYI(1, ("In SetTimes"));
4578
4579SetTimesRetry:
4580 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4581 (void **) &pSMBr);
4582 if (rc)
4583 return rc;
4584
4585 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4586 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004587 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004588 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 name_len++; /* trailing null */
4590 name_len *= 2;
4591 } else { /* BB improve the check for buffer overruns BB */
4592 name_len = strnlen(fileName, PATH_MAX);
4593 name_len++; /* trailing null */
4594 strncpy(pSMB->FileName, fileName, name_len);
4595 }
4596
4597 params = 6 + name_len;
4598 count = sizeof (FILE_BASIC_INFO);
4599 pSMB->MaxParameterCount = cpu_to_le16(2);
4600 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4601 pSMB->MaxSetupCount = 0;
4602 pSMB->Reserved = 0;
4603 pSMB->Flags = 0;
4604 pSMB->Timeout = 0;
4605 pSMB->Reserved2 = 0;
4606 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4607 InformationLevel) - 4;
4608 offset = param_offset + params;
4609 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4610 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4611 pSMB->DataOffset = cpu_to_le16(offset);
4612 pSMB->SetupCount = 1;
4613 pSMB->Reserved3 = 0;
4614 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4615 byte_count = 3 /* pad */ + params + count;
4616
4617 pSMB->DataCount = cpu_to_le16(count);
4618 pSMB->ParameterCount = cpu_to_le16(params);
4619 pSMB->TotalDataCount = pSMB->DataCount;
4620 pSMB->TotalParameterCount = pSMB->ParameterCount;
4621 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4622 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4623 else
4624 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4625 pSMB->Reserved4 = 0;
4626 pSMB->hdr.smb_buf_length += byte_count;
4627 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4628 pSMB->ByteCount = cpu_to_le16(byte_count);
4629 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4630 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4631 if (rc) {
4632 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4633 }
4634
4635 cifs_buf_release(pSMB);
4636
4637 if (rc == -EAGAIN)
4638 goto SetTimesRetry;
4639
4640 return rc;
4641}
4642
4643/* Can not be used to set time stamps yet (due to old DOS time format) */
4644/* Can be used to set attributes */
4645#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4646 handling it anyway and NT4 was what we thought it would be needed for
4647 Do not delete it until we prove whether needed for Win9x though */
4648int
4649CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4650 __u16 dos_attrs, const struct nls_table *nls_codepage)
4651{
4652 SETATTR_REQ *pSMB = NULL;
4653 SETATTR_RSP *pSMBr = NULL;
4654 int rc = 0;
4655 int bytes_returned;
4656 int name_len;
4657
4658 cFYI(1, ("In SetAttrLegacy"));
4659
4660SetAttrLgcyRetry:
4661 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4662 (void **) &pSMBr);
4663 if (rc)
4664 return rc;
4665
4666 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4667 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004668 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 PATH_MAX, nls_codepage);
4670 name_len++; /* trailing null */
4671 name_len *= 2;
4672 } else { /* BB improve the check for buffer overruns BB */
4673 name_len = strnlen(fileName, PATH_MAX);
4674 name_len++; /* trailing null */
4675 strncpy(pSMB->fileName, fileName, name_len);
4676 }
4677 pSMB->attr = cpu_to_le16(dos_attrs);
4678 pSMB->BufferFormat = 0x04;
4679 pSMB->hdr.smb_buf_length += name_len + 1;
4680 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4681 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4682 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4683 if (rc) {
4684 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4685 }
4686
4687 cifs_buf_release(pSMB);
4688
4689 if (rc == -EAGAIN)
4690 goto SetAttrLgcyRetry;
4691
4692 return rc;
4693}
4694#endif /* temporarily unneeded SetAttr legacy function */
4695
4696int
4697CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004698 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4699 dev_t device, const struct nls_table *nls_codepage,
4700 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701{
4702 TRANSACTION2_SPI_REQ *pSMB = NULL;
4703 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4704 int name_len;
4705 int rc = 0;
4706 int bytes_returned = 0;
4707 FILE_UNIX_BASIC_INFO *data_offset;
4708 __u16 params, param_offset, offset, count, byte_count;
4709
4710 cFYI(1, ("In SetUID/GID/Mode"));
4711setPermsRetry:
4712 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4713 (void **) &pSMBr);
4714 if (rc)
4715 return rc;
4716
4717 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4718 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004719 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004720 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 name_len++; /* trailing null */
4722 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004723 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 name_len = strnlen(fileName, PATH_MAX);
4725 name_len++; /* trailing null */
4726 strncpy(pSMB->FileName, fileName, name_len);
4727 }
4728
4729 params = 6 + name_len;
4730 count = sizeof (FILE_UNIX_BASIC_INFO);
4731 pSMB->MaxParameterCount = cpu_to_le16(2);
4732 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4733 pSMB->MaxSetupCount = 0;
4734 pSMB->Reserved = 0;
4735 pSMB->Flags = 0;
4736 pSMB->Timeout = 0;
4737 pSMB->Reserved2 = 0;
4738 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4739 InformationLevel) - 4;
4740 offset = param_offset + params;
4741 data_offset =
4742 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4743 offset);
4744 memset(data_offset, 0, count);
4745 pSMB->DataOffset = cpu_to_le16(offset);
4746 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4747 pSMB->SetupCount = 1;
4748 pSMB->Reserved3 = 0;
4749 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4750 byte_count = 3 /* pad */ + params + count;
4751 pSMB->ParameterCount = cpu_to_le16(params);
4752 pSMB->DataCount = cpu_to_le16(count);
4753 pSMB->TotalParameterCount = pSMB->ParameterCount;
4754 pSMB->TotalDataCount = pSMB->DataCount;
4755 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4756 pSMB->Reserved4 = 0;
4757 pSMB->hdr.smb_buf_length += byte_count;
4758 data_offset->Uid = cpu_to_le64(uid);
4759 data_offset->Gid = cpu_to_le64(gid);
4760 /* better to leave device as zero when it is */
4761 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4762 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4763 data_offset->Permissions = cpu_to_le64(mode);
4764
4765 if(S_ISREG(mode))
4766 data_offset->Type = cpu_to_le32(UNIX_FILE);
4767 else if(S_ISDIR(mode))
4768 data_offset->Type = cpu_to_le32(UNIX_DIR);
4769 else if(S_ISLNK(mode))
4770 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4771 else if(S_ISCHR(mode))
4772 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4773 else if(S_ISBLK(mode))
4774 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4775 else if(S_ISFIFO(mode))
4776 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4777 else if(S_ISSOCK(mode))
4778 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4779
4780
4781 pSMB->ByteCount = cpu_to_le16(byte_count);
4782 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4783 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4784 if (rc) {
4785 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4786 }
4787
4788 if (pSMB)
4789 cifs_buf_release(pSMB);
4790 if (rc == -EAGAIN)
4791 goto setPermsRetry;
4792 return rc;
4793}
4794
4795int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004796 const int notify_subdirs, const __u16 netfid,
4797 __u32 filter, struct file * pfile, int multishot,
4798 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799{
4800 int rc = 0;
4801 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004802 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004803 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 int bytes_returned;
4805
4806 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4807 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4808 (void **) &pSMBr);
4809 if (rc)
4810 return rc;
4811
4812 pSMB->TotalParameterCount = 0 ;
4813 pSMB->TotalDataCount = 0;
4814 pSMB->MaxParameterCount = cpu_to_le32(2);
4815 /* BB find exact data count max from sess structure BB */
4816 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004817/* BB VERIFY verify which is correct for above BB */
4818 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4819 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4820
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 pSMB->MaxSetupCount = 4;
4822 pSMB->Reserved = 0;
4823 pSMB->ParameterOffset = 0;
4824 pSMB->DataCount = 0;
4825 pSMB->DataOffset = 0;
4826 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4827 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4828 pSMB->ParameterCount = pSMB->TotalParameterCount;
4829 if(notify_subdirs)
4830 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4831 pSMB->Reserved2 = 0;
4832 pSMB->CompletionFilter = cpu_to_le32(filter);
4833 pSMB->Fid = netfid; /* file handle always le */
4834 pSMB->ByteCount = 0;
4835
4836 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4837 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4838 if (rc) {
4839 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004840 } else {
4841 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004842 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004843 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004844 sizeof(struct dir_notify_req),
4845 GFP_KERNEL);
4846 if(dnotify_req) {
4847 dnotify_req->Pid = pSMB->hdr.Pid;
4848 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4849 dnotify_req->Mid = pSMB->hdr.Mid;
4850 dnotify_req->Tid = pSMB->hdr.Tid;
4851 dnotify_req->Uid = pSMB->hdr.Uid;
4852 dnotify_req->netfid = netfid;
4853 dnotify_req->pfile = pfile;
4854 dnotify_req->filter = filter;
4855 dnotify_req->multishot = multishot;
4856 spin_lock(&GlobalMid_Lock);
4857 list_add_tail(&dnotify_req->lhead,
4858 &GlobalDnotifyReqList);
4859 spin_unlock(&GlobalMid_Lock);
4860 } else
4861 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 }
4863 cifs_buf_release(pSMB);
4864 return rc;
4865}
4866#ifdef CONFIG_CIFS_XATTR
4867ssize_t
4868CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4869 const unsigned char *searchName,
4870 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004871 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872{
4873 /* BB assumes one setup word */
4874 TRANSACTION2_QPI_REQ *pSMB = NULL;
4875 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4876 int rc = 0;
4877 int bytes_returned;
4878 int name_len;
4879 struct fea * temp_fea;
4880 char * temp_ptr;
4881 __u16 params, byte_count;
4882
4883 cFYI(1, ("In Query All EAs path %s", searchName));
4884QAllEAsRetry:
4885 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4886 (void **) &pSMBr);
4887 if (rc)
4888 return rc;
4889
4890 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4891 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004892 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004893 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 name_len++; /* trailing null */
4895 name_len *= 2;
4896 } else { /* BB improve the check for buffer overruns BB */
4897 name_len = strnlen(searchName, PATH_MAX);
4898 name_len++; /* trailing null */
4899 strncpy(pSMB->FileName, searchName, name_len);
4900 }
4901
4902 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4903 pSMB->TotalDataCount = 0;
4904 pSMB->MaxParameterCount = cpu_to_le16(2);
4905 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4906 pSMB->MaxSetupCount = 0;
4907 pSMB->Reserved = 0;
4908 pSMB->Flags = 0;
4909 pSMB->Timeout = 0;
4910 pSMB->Reserved2 = 0;
4911 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4912 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4913 pSMB->DataCount = 0;
4914 pSMB->DataOffset = 0;
4915 pSMB->SetupCount = 1;
4916 pSMB->Reserved3 = 0;
4917 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4918 byte_count = params + 1 /* pad */ ;
4919 pSMB->TotalParameterCount = cpu_to_le16(params);
4920 pSMB->ParameterCount = pSMB->TotalParameterCount;
4921 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4922 pSMB->Reserved4 = 0;
4923 pSMB->hdr.smb_buf_length += byte_count;
4924 pSMB->ByteCount = cpu_to_le16(byte_count);
4925
4926 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4927 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4928 if (rc) {
4929 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4930 } else { /* decode response */
4931 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4932
4933 /* BB also check enough total bytes returned */
4934 /* BB we need to improve the validity checking
4935 of these trans2 responses */
4936 if (rc || (pSMBr->ByteCount < 4))
4937 rc = -EIO; /* bad smb */
4938 /* else if (pFindData){
4939 memcpy((char *) pFindData,
4940 (char *) &pSMBr->hdr.Protocol +
4941 data_offset, kl);
4942 }*/ else {
4943 /* check that length of list is not more than bcc */
4944 /* check that each entry does not go beyond length
4945 of list */
4946 /* check that each element of each entry does not
4947 go beyond end of list */
4948 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4949 struct fealist * ea_response_data;
4950 rc = 0;
4951 /* validate_trans2_offsets() */
4952 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4953 ea_response_data = (struct fealist *)
4954 (((char *) &pSMBr->hdr.Protocol) +
4955 data_offset);
4956 name_len = le32_to_cpu(ea_response_data->list_len);
4957 cFYI(1,("ea length %d", name_len));
4958 if(name_len <= 8) {
4959 /* returned EA size zeroed at top of function */
4960 cFYI(1,("empty EA list returned from server"));
4961 } else {
4962 /* account for ea list len */
4963 name_len -= 4;
4964 temp_fea = ea_response_data->list;
4965 temp_ptr = (char *)temp_fea;
4966 while(name_len > 0) {
4967 __u16 value_len;
4968 name_len -= 4;
4969 temp_ptr += 4;
4970 rc += temp_fea->name_len;
4971 /* account for prefix user. and trailing null */
4972 rc = rc + 5 + 1;
4973 if(rc<(int)buf_size) {
4974 memcpy(EAData,"user.",5);
4975 EAData+=5;
4976 memcpy(EAData,temp_ptr,temp_fea->name_len);
4977 EAData+=temp_fea->name_len;
4978 /* null terminate name */
4979 *EAData = 0;
4980 EAData = EAData + 1;
4981 } else if(buf_size == 0) {
4982 /* skip copy - calc size only */
4983 } else {
4984 /* stop before overrun buffer */
4985 rc = -ERANGE;
4986 break;
4987 }
4988 name_len -= temp_fea->name_len;
4989 temp_ptr += temp_fea->name_len;
4990 /* account for trailing null */
4991 name_len--;
4992 temp_ptr++;
4993 value_len = le16_to_cpu(temp_fea->value_len);
4994 name_len -= value_len;
4995 temp_ptr += value_len;
4996 /* BB check that temp_ptr is still within smb BB*/
4997 /* no trailing null to account for in value len */
4998 /* go on to next EA */
4999 temp_fea = (struct fea *)temp_ptr;
5000 }
5001 }
5002 }
5003 }
5004 if (pSMB)
5005 cifs_buf_release(pSMB);
5006 if (rc == -EAGAIN)
5007 goto QAllEAsRetry;
5008
5009 return (ssize_t)rc;
5010}
5011
5012ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5013 const unsigned char * searchName,const unsigned char * ea_name,
5014 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005015 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016{
5017 TRANSACTION2_QPI_REQ *pSMB = NULL;
5018 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5019 int rc = 0;
5020 int bytes_returned;
5021 int name_len;
5022 struct fea * temp_fea;
5023 char * temp_ptr;
5024 __u16 params, byte_count;
5025
5026 cFYI(1, ("In Query EA path %s", searchName));
5027QEARetry:
5028 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5029 (void **) &pSMBr);
5030 if (rc)
5031 return rc;
5032
5033 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5034 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005035 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005036 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037 name_len++; /* trailing null */
5038 name_len *= 2;
5039 } else { /* BB improve the check for buffer overruns BB */
5040 name_len = strnlen(searchName, PATH_MAX);
5041 name_len++; /* trailing null */
5042 strncpy(pSMB->FileName, searchName, name_len);
5043 }
5044
5045 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5046 pSMB->TotalDataCount = 0;
5047 pSMB->MaxParameterCount = cpu_to_le16(2);
5048 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5049 pSMB->MaxSetupCount = 0;
5050 pSMB->Reserved = 0;
5051 pSMB->Flags = 0;
5052 pSMB->Timeout = 0;
5053 pSMB->Reserved2 = 0;
5054 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5055 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5056 pSMB->DataCount = 0;
5057 pSMB->DataOffset = 0;
5058 pSMB->SetupCount = 1;
5059 pSMB->Reserved3 = 0;
5060 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5061 byte_count = params + 1 /* pad */ ;
5062 pSMB->TotalParameterCount = cpu_to_le16(params);
5063 pSMB->ParameterCount = pSMB->TotalParameterCount;
5064 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5065 pSMB->Reserved4 = 0;
5066 pSMB->hdr.smb_buf_length += byte_count;
5067 pSMB->ByteCount = cpu_to_le16(byte_count);
5068
5069 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5070 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5071 if (rc) {
5072 cFYI(1, ("Send error in Query EA = %d", rc));
5073 } else { /* decode response */
5074 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5075
5076 /* BB also check enough total bytes returned */
5077 /* BB we need to improve the validity checking
5078 of these trans2 responses */
5079 if (rc || (pSMBr->ByteCount < 4))
5080 rc = -EIO; /* bad smb */
5081 /* else if (pFindData){
5082 memcpy((char *) pFindData,
5083 (char *) &pSMBr->hdr.Protocol +
5084 data_offset, kl);
5085 }*/ else {
5086 /* check that length of list is not more than bcc */
5087 /* check that each entry does not go beyond length
5088 of list */
5089 /* check that each element of each entry does not
5090 go beyond end of list */
5091 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5092 struct fealist * ea_response_data;
5093 rc = -ENODATA;
5094 /* validate_trans2_offsets() */
5095 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5096 ea_response_data = (struct fealist *)
5097 (((char *) &pSMBr->hdr.Protocol) +
5098 data_offset);
5099 name_len = le32_to_cpu(ea_response_data->list_len);
5100 cFYI(1,("ea length %d", name_len));
5101 if(name_len <= 8) {
5102 /* returned EA size zeroed at top of function */
5103 cFYI(1,("empty EA list returned from server"));
5104 } else {
5105 /* account for ea list len */
5106 name_len -= 4;
5107 temp_fea = ea_response_data->list;
5108 temp_ptr = (char *)temp_fea;
5109 /* loop through checking if we have a matching
5110 name and then return the associated value */
5111 while(name_len > 0) {
5112 __u16 value_len;
5113 name_len -= 4;
5114 temp_ptr += 4;
5115 value_len = le16_to_cpu(temp_fea->value_len);
5116 /* BB validate that value_len falls within SMB,
5117 even though maximum for name_len is 255 */
5118 if(memcmp(temp_fea->name,ea_name,
5119 temp_fea->name_len) == 0) {
5120 /* found a match */
5121 rc = value_len;
5122 /* account for prefix user. and trailing null */
5123 if(rc<=(int)buf_size) {
5124 memcpy(ea_value,
5125 temp_fea->name+temp_fea->name_len+1,
5126 rc);
5127 /* ea values, unlike ea names,
5128 are not null terminated */
5129 } else if(buf_size == 0) {
5130 /* skip copy - calc size only */
5131 } else {
5132 /* stop before overrun buffer */
5133 rc = -ERANGE;
5134 }
5135 break;
5136 }
5137 name_len -= temp_fea->name_len;
5138 temp_ptr += temp_fea->name_len;
5139 /* account for trailing null */
5140 name_len--;
5141 temp_ptr++;
5142 name_len -= value_len;
5143 temp_ptr += value_len;
5144 /* no trailing null to account for in value len */
5145 /* go on to next EA */
5146 temp_fea = (struct fea *)temp_ptr;
5147 }
5148 }
5149 }
5150 }
5151 if (pSMB)
5152 cifs_buf_release(pSMB);
5153 if (rc == -EAGAIN)
5154 goto QEARetry;
5155
5156 return (ssize_t)rc;
5157}
5158
5159int
5160CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5161 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005162 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5163 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164{
5165 struct smb_com_transaction2_spi_req *pSMB = NULL;
5166 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5167 struct fealist *parm_data;
5168 int name_len;
5169 int rc = 0;
5170 int bytes_returned = 0;
5171 __u16 params, param_offset, byte_count, offset, count;
5172
5173 cFYI(1, ("In SetEA"));
5174SetEARetry:
5175 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5176 (void **) &pSMBr);
5177 if (rc)
5178 return rc;
5179
5180 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5181 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005182 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005183 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 name_len++; /* trailing null */
5185 name_len *= 2;
5186 } else { /* BB improve the check for buffer overruns BB */
5187 name_len = strnlen(fileName, PATH_MAX);
5188 name_len++; /* trailing null */
5189 strncpy(pSMB->FileName, fileName, name_len);
5190 }
5191
5192 params = 6 + name_len;
5193
5194 /* done calculating parms using name_len of file name,
5195 now use name_len to calculate length of ea name
5196 we are going to create in the inode xattrs */
5197 if(ea_name == NULL)
5198 name_len = 0;
5199 else
5200 name_len = strnlen(ea_name,255);
5201
5202 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5203 pSMB->MaxParameterCount = cpu_to_le16(2);
5204 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5205 pSMB->MaxSetupCount = 0;
5206 pSMB->Reserved = 0;
5207 pSMB->Flags = 0;
5208 pSMB->Timeout = 0;
5209 pSMB->Reserved2 = 0;
5210 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5211 InformationLevel) - 4;
5212 offset = param_offset + params;
5213 pSMB->InformationLevel =
5214 cpu_to_le16(SMB_SET_FILE_EA);
5215
5216 parm_data =
5217 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5218 offset);
5219 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5220 pSMB->DataOffset = cpu_to_le16(offset);
5221 pSMB->SetupCount = 1;
5222 pSMB->Reserved3 = 0;
5223 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5224 byte_count = 3 /* pad */ + params + count;
5225 pSMB->DataCount = cpu_to_le16(count);
5226 parm_data->list_len = cpu_to_le32(count);
5227 parm_data->list[0].EA_flags = 0;
5228 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005229 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 /* EA names are always ASCII */
5231 if(ea_name)
5232 strncpy(parm_data->list[0].name,ea_name,name_len);
5233 parm_data->list[0].name[name_len] = 0;
5234 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5235 /* caller ensures that ea_value_len is less than 64K but
5236 we need to ensure that it fits within the smb */
5237
5238 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5239 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5240 if(ea_value_len)
5241 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5242
5243 pSMB->TotalDataCount = pSMB->DataCount;
5244 pSMB->ParameterCount = cpu_to_le16(params);
5245 pSMB->TotalParameterCount = pSMB->ParameterCount;
5246 pSMB->Reserved4 = 0;
5247 pSMB->hdr.smb_buf_length += byte_count;
5248 pSMB->ByteCount = cpu_to_le16(byte_count);
5249 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5250 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5251 if (rc) {
5252 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5253 }
5254
5255 cifs_buf_release(pSMB);
5256
5257 if (rc == -EAGAIN)
5258 goto SetEARetry;
5259
5260 return rc;
5261}
5262
5263#endif