blob: 6e004587fa483d92cafa5f31e37bf6493e401c3f [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 }
Steve French25ee4a92006-09-30 00:54:23 +0000476 tmp = le16_to_cpu(rsp->ServerTimeZone);
477 if (tmp == (int)0xffff) {
478 /* OS/2 often does not set timezone therefore
479 * we must use server time to calc time zone.
480 * Could deviate slightly from the right zone. Not easy
481 * to adjust, since timezones are not always a multiple
482 * of 60 (sometimes 30 minutes - are there smaller?)
483 */
484 struct timespec ts, utc;
485 utc = CURRENT_TIME;
486 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
487 le16_to_cpu(rsp->SrvTime.Time));
488 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
489 (int)ts.tv_sec, (int)utc.tv_sec,
490 (int)(utc.tv_sec - ts.tv_sec)));
491 tmp = (int)(utc.tv_sec - ts.tv_sec);
492 adjust = tmp < 0 ? -29 : 29;
493 tmp = ((tmp + adjust) / 60) * 60;
Steve French175ec9e2006-09-30 01:07:38 +0000494 server->timeAdj = tmp;
Steve French25ee4a92006-09-30 00:54:23 +0000495 } else {
Steve French175ec9e2006-09-30 01:07:38 +0000496 server->timeAdj = tmp * 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000497 }
Steve French175ec9e2006-09-30 01:07:38 +0000498 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000499
Steve French39798772006-05-31 22:40:51 +0000500
Steve French254e55e2006-06-04 05:53:15 +0000501 /* BB get server time for time conversions and add
502 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000503
Steve French25ee4a92006-09-30 00:54:23 +0000504 if (rsp->EncryptionKeyLength ==
505 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000506 memcpy(server->cryptKey, rsp->EncryptionKey,
507 CIFS_CRYPTO_KEY_SIZE);
508 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
509 rc = -EIO; /* need cryptkey unless plain text */
510 goto neg_err_exit;
511 }
Steve French39798772006-05-31 22:40:51 +0000512
Steve French254e55e2006-06-04 05:53:15 +0000513 cFYI(1,("LANMAN negotiated"));
514 /* we will not end up setting signing flags - as no signing
515 was in LANMAN and server did not return the flags on */
516 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000517#else /* weak security disabled */
Steve French254e55e2006-06-04 05:53:15 +0000518 } else if(pSMBr->hdr.WordCount == 13) {
519 cERROR(1,("mount failed, cifs module not built "
520 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000521 rc = -EOPNOTSUPP;
522#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000523 goto neg_err_exit;
524 } else if(pSMBr->hdr.WordCount != 17) {
525 /* unknown wct */
526 rc = -EOPNOTSUPP;
527 goto neg_err_exit;
528 }
529 /* else wct == 17 NTLM */
530 server->secMode = pSMBr->SecurityMode;
531 if((server->secMode & SECMODE_USER) == 0)
532 cFYI(1,("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000533
Steve French254e55e2006-06-04 05:53:15 +0000534 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000535#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000536 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000537#endif /* CIFS_WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000538 cERROR(1,("Server requests plain text password"
539 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000540
Steve Frenchf40c5622006-06-28 00:13:38 +0000541 if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000542 server->secType = NTLMv2;
Steve Frenchf40c5622006-06-28 00:13:38 +0000543 else if(secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000544 server->secType = NTLM;
Steve Frenchf40c5622006-06-28 00:13:38 +0000545 else if(secFlags & CIFSSEC_MAY_NTLMV2)
546 server->secType = NTLMv2;
547 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000548
Steve French254e55e2006-06-04 05:53:15 +0000549 /* one byte, so no need to convert this or EncryptionKeyLen from
550 little endian */
551 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
552 /* probably no need to store and check maxvcs */
553 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000555 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
556 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
557 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
558 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve French175ec9e2006-09-30 01:07:38 +0000559 server->timeAdj = le16_to_cpu(pSMBr->ServerTimeZone) * 60;
Steve French254e55e2006-06-04 05:53:15 +0000560 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
561 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
562 CIFS_CRYPTO_KEY_SIZE);
563 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
564 && (pSMBr->EncryptionKeyLength == 0)) {
565 /* decode security blob */
566 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
567 rc = -EIO; /* no crypt key only if plain text pwd */
568 goto neg_err_exit;
569 }
570
571 /* BB might be helpful to save off the domain of server here */
572
573 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
574 (server->capabilities & CAP_EXTENDED_SECURITY)) {
575 count = pSMBr->ByteCount;
576 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000578 else if (count == 16) {
579 server->secType = RawNTLMSSP;
580 if (server->socketUseCount.counter > 1) {
581 if (memcmp(server->server_GUID,
582 pSMBr->u.extended_response.
583 GUID, 16) != 0) {
584 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000586 pSMBr->u.extended_response.GUID,
587 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 }
Steve French254e55e2006-06-04 05:53:15 +0000589 } else
590 memcpy(server->server_GUID,
591 pSMBr->u.extended_response.GUID, 16);
592 } else {
593 rc = decode_negTokenInit(pSMBr->u.extended_response.
594 SecurityBlob,
595 count - 16,
596 &server->secType);
597 if(rc == 1) {
598 /* BB Need to fill struct for sessetup here */
599 rc = -EOPNOTSUPP;
600 } else {
601 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 }
Steve French254e55e2006-06-04 05:53:15 +0000604 } else
605 server->capabilities &= ~CAP_EXTENDED_SECURITY;
606
Steve French6344a422006-06-12 04:18:35 +0000607#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000608signing_check:
Steve French6344a422006-06-12 04:18:35 +0000609#endif
Steve French254e55e2006-06-04 05:53:15 +0000610 if(sign_CIFS_PDUs == FALSE) {
611 if(server->secMode & SECMODE_SIGN_REQUIRED)
612 cERROR(1,("Server requires "
613 "/proc/fs/cifs/PacketSigningEnabled to be on"));
614 server->secMode &=
615 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
616 } else if(sign_CIFS_PDUs == 1) {
617 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
618 server->secMode &=
619 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
620 } else if(sign_CIFS_PDUs == 2) {
621 if((server->secMode &
622 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
623 cERROR(1,("signing required but server lacks support"));
624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 }
Steve French39798772006-05-31 22:40:51 +0000626neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700627 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000628
629 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 return rc;
631}
632
633int
634CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
635{
636 struct smb_hdr *smb_buffer;
637 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
638 int rc = 0;
639 int length;
640
641 cFYI(1, ("In tree disconnect"));
642 /*
643 * If last user of the connection and
644 * connection alive - disconnect it
645 * If this is the last connection on the server session disconnect it
646 * (and inside session disconnect we should check if tcp socket needs
647 * to be freed and kernel thread woken up).
648 */
649 if (tcon)
650 down(&tcon->tconSem);
651 else
652 return -EIO;
653
654 atomic_dec(&tcon->useCount);
655 if (atomic_read(&tcon->useCount) > 0) {
656 up(&tcon->tconSem);
657 return -EBUSY;
658 }
659
660 /* No need to return error on this operation if tid invalidated and
661 closed on server already e.g. due to tcp session crashing */
662 if(tcon->tidStatus == CifsNeedReconnect) {
663 up(&tcon->tconSem);
664 return 0;
665 }
666
667 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
668 up(&tcon->tconSem);
669 return -EIO;
670 }
Steve French09d1db52005-04-28 22:41:08 -0700671 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
672 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 if (rc) {
674 up(&tcon->tconSem);
675 return rc;
676 } else {
677 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
680 &length, 0);
681 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700682 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684 if (smb_buffer)
685 cifs_small_buf_release(smb_buffer);
686 up(&tcon->tconSem);
687
688 /* No need to return error on this operation if tid invalidated and
689 closed on server already e.g. due to tcp session crashing */
690 if (rc == -EAGAIN)
691 rc = 0;
692
693 return rc;
694}
695
696int
697CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
698{
699 struct smb_hdr *smb_buffer_response;
700 LOGOFF_ANDX_REQ *pSMB;
701 int rc = 0;
702 int length;
703
704 cFYI(1, ("In SMBLogoff for session disconnect"));
705 if (ses)
706 down(&ses->sesSem);
707 else
708 return -EIO;
709
710 atomic_dec(&ses->inUse);
711 if (atomic_read(&ses->inUse) > 0) {
712 up(&ses->sesSem);
713 return -EBUSY;
714 }
715 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
716 if (rc) {
717 up(&ses->sesSem);
718 return rc;
719 }
720
721 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
722
723 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700724 pSMB->hdr.Mid = GetNextMid(ses->server);
725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 if(ses->server->secMode &
727 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
728 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
729 }
730
731 pSMB->hdr.Uid = ses->Suid;
732
733 pSMB->AndXCommand = 0xFF;
734 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
735 smb_buffer_response, &length, 0);
736 if (ses->server) {
737 atomic_dec(&ses->server->socketUseCount);
738 if (atomic_read(&ses->server->socketUseCount) == 0) {
739 spin_lock(&GlobalMid_Lock);
740 ses->server->tcpStatus = CifsExiting;
741 spin_unlock(&GlobalMid_Lock);
742 rc = -ESHUTDOWN;
743 }
744 }
Steve Frencha59c6582005-08-17 12:12:19 -0700745 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700746 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 /* if session dead then we do not need to do ulogoff,
749 since server closed smb session, no sense reporting
750 error */
751 if (rc == -EAGAIN)
752 rc = 0;
753 return rc;
754}
755
756int
Steve French737b7582005-04-28 22:41:06 -0700757CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
758 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
760 DELETE_FILE_REQ *pSMB = NULL;
761 DELETE_FILE_RSP *pSMBr = NULL;
762 int rc = 0;
763 int bytes_returned;
764 int name_len;
765
766DelFileRetry:
767 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
768 (void **) &pSMBr);
769 if (rc)
770 return rc;
771
772 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
773 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500774 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700775 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 name_len++; /* trailing null */
777 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700778 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 name_len = strnlen(fileName, PATH_MAX);
780 name_len++; /* trailing null */
781 strncpy(pSMB->fileName, fileName, name_len);
782 }
783 pSMB->SearchAttributes =
784 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
785 pSMB->BufferFormat = 0x04;
786 pSMB->hdr.smb_buf_length += name_len + 1;
787 pSMB->ByteCount = cpu_to_le16(name_len + 1);
788 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
789 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700790 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 if (rc) {
792 cFYI(1, ("Error in RMFile = %d", rc));
793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 cifs_buf_release(pSMB);
796 if (rc == -EAGAIN)
797 goto DelFileRetry;
798
799 return rc;
800}
801
802int
Steve French737b7582005-04-28 22:41:06 -0700803CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
804 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
806 DELETE_DIRECTORY_REQ *pSMB = NULL;
807 DELETE_DIRECTORY_RSP *pSMBr = NULL;
808 int rc = 0;
809 int bytes_returned;
810 int name_len;
811
812 cFYI(1, ("In CIFSSMBRmDir"));
813RmDirRetry:
814 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
815 (void **) &pSMBr);
816 if (rc)
817 return rc;
818
819 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700820 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
821 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 name_len++; /* trailing null */
823 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700824 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 name_len = strnlen(dirName, PATH_MAX);
826 name_len++; /* trailing null */
827 strncpy(pSMB->DirName, dirName, name_len);
828 }
829
830 pSMB->BufferFormat = 0x04;
831 pSMB->hdr.smb_buf_length += name_len + 1;
832 pSMB->ByteCount = cpu_to_le16(name_len + 1);
833 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
834 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700835 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 if (rc) {
837 cFYI(1, ("Error in RMDir = %d", rc));
838 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
840 cifs_buf_release(pSMB);
841 if (rc == -EAGAIN)
842 goto RmDirRetry;
843 return rc;
844}
845
846int
847CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700848 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849{
850 int rc = 0;
851 CREATE_DIRECTORY_REQ *pSMB = NULL;
852 CREATE_DIRECTORY_RSP *pSMBr = NULL;
853 int bytes_returned;
854 int name_len;
855
856 cFYI(1, ("In CIFSSMBMkDir"));
857MkDirRetry:
858 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
859 (void **) &pSMBr);
860 if (rc)
861 return rc;
862
863 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500864 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700865 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 name_len++; /* trailing null */
867 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700868 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 name_len = strnlen(name, PATH_MAX);
870 name_len++; /* trailing null */
871 strncpy(pSMB->DirName, name, name_len);
872 }
873
874 pSMB->BufferFormat = 0x04;
875 pSMB->hdr.smb_buf_length += name_len + 1;
876 pSMB->ByteCount = cpu_to_le16(name_len + 1);
877 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
878 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700879 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (rc) {
881 cFYI(1, ("Error in Mkdir = %d", rc));
882 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700883
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 cifs_buf_release(pSMB);
885 if (rc == -EAGAIN)
886 goto MkDirRetry;
887 return rc;
888}
889
Steve Frencha9d02ad2005-08-24 23:06:05 -0700890static __u16 convert_disposition(int disposition)
891{
892 __u16 ofun = 0;
893
894 switch (disposition) {
895 case FILE_SUPERSEDE:
896 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
897 break;
898 case FILE_OPEN:
899 ofun = SMBOPEN_OAPPEND;
900 break;
901 case FILE_CREATE:
902 ofun = SMBOPEN_OCREATE;
903 break;
904 case FILE_OPEN_IF:
905 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
906 break;
907 case FILE_OVERWRITE:
908 ofun = SMBOPEN_OTRUNC;
909 break;
910 case FILE_OVERWRITE_IF:
911 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
912 break;
913 default:
914 cFYI(1,("unknown disposition %d",disposition));
915 ofun = SMBOPEN_OAPPEND; /* regular open */
916 }
917 return ofun;
918}
919
920int
921SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
922 const char *fileName, const int openDisposition,
923 const int access_flags, const int create_options, __u16 * netfid,
924 int *pOplock, FILE_ALL_INFO * pfile_info,
925 const struct nls_table *nls_codepage, int remap)
926{
927 int rc = -EACCES;
928 OPENX_REQ *pSMB = NULL;
929 OPENX_RSP *pSMBr = NULL;
930 int bytes_returned;
931 int name_len;
932 __u16 count;
933
934OldOpenRetry:
935 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
936 (void **) &pSMBr);
937 if (rc)
938 return rc;
939
940 pSMB->AndXCommand = 0xFF; /* none */
941
942 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
943 count = 1; /* account for one byte pad to word boundary */
944 name_len =
945 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
946 fileName, PATH_MAX, nls_codepage, remap);
947 name_len++; /* trailing null */
948 name_len *= 2;
949 } else { /* BB improve check for buffer overruns BB */
950 count = 0; /* no pad */
951 name_len = strnlen(fileName, PATH_MAX);
952 name_len++; /* trailing null */
953 strncpy(pSMB->fileName, fileName, name_len);
954 }
955 if (*pOplock & REQ_OPLOCK)
956 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
957 else if (*pOplock & REQ_BATCHOPLOCK) {
958 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
959 }
960 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
961 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
962 /* 0 = read
963 1 = write
964 2 = rw
965 3 = execute
966 */
967 pSMB->Mode = cpu_to_le16(2);
968 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
969 /* set file as system file if special file such
970 as fifo and server expecting SFU style and
971 no Unix extensions */
972
973 if(create_options & CREATE_OPTION_SPECIAL)
974 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
975 else
Steve French3e87d802005-09-18 20:49:21 -0700976 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700977
978 /* if ((omode & S_IWUGO) == 0)
979 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
980 /* Above line causes problems due to vfs splitting create into two
981 pieces - need to set mode after file created not while it is
982 being created */
983
984 /* BB FIXME BB */
985/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
986 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700987
988 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700989 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700990 count += name_len;
991 pSMB->hdr.smb_buf_length += count;
992
993 pSMB->ByteCount = cpu_to_le16(count);
994 /* long_op set to 1 to allow for oplock break timeouts */
995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
996 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
997 cifs_stats_inc(&tcon->num_opens);
998 if (rc) {
999 cFYI(1, ("Error in Open = %d", rc));
1000 } else {
1001 /* BB verify if wct == 15 */
1002
1003/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1004
1005 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1006 /* Let caller know file was created so we can set the mode. */
1007 /* Do we care about the CreateAction in any other cases? */
1008 /* BB FIXME BB */
1009/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1010 *pOplock |= CIFS_CREATE_ACTION; */
1011 /* BB FIXME END */
1012
1013 if(pfile_info) {
1014 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1015 pfile_info->LastAccessTime = 0; /* BB fixme */
1016 pfile_info->LastWriteTime = 0; /* BB fixme */
1017 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001018 pfile_info->Attributes =
1019 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001020 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001021 pfile_info->AllocationSize =
1022 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1023 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001024 pfile_info->NumberOfLinks = cpu_to_le32(1);
1025 }
1026 }
1027
1028 cifs_buf_release(pSMB);
1029 if (rc == -EAGAIN)
1030 goto OldOpenRetry;
1031 return rc;
1032}
1033
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034int
1035CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1036 const char *fileName, const int openDisposition,
1037 const int access_flags, const int create_options, __u16 * netfid,
1038 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001039 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040{
1041 int rc = -EACCES;
1042 OPEN_REQ *pSMB = NULL;
1043 OPEN_RSP *pSMBr = NULL;
1044 int bytes_returned;
1045 int name_len;
1046 __u16 count;
1047
1048openRetry:
1049 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1050 (void **) &pSMBr);
1051 if (rc)
1052 return rc;
1053
1054 pSMB->AndXCommand = 0xFF; /* none */
1055
1056 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1057 count = 1; /* account for one byte pad to word boundary */
1058 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001059 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001060 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 name_len++; /* trailing null */
1062 name_len *= 2;
1063 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001064 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 count = 0; /* no pad */
1066 name_len = strnlen(fileName, PATH_MAX);
1067 name_len++; /* trailing null */
1068 pSMB->NameLength = cpu_to_le16(name_len);
1069 strncpy(pSMB->fileName, fileName, name_len);
1070 }
1071 if (*pOplock & REQ_OPLOCK)
1072 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1073 else if (*pOplock & REQ_BATCHOPLOCK) {
1074 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1075 }
1076 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1077 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001078 /* set file as system file if special file such
1079 as fifo and server expecting SFU style and
1080 no Unix extensions */
1081 if(create_options & CREATE_OPTION_SPECIAL)
1082 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1083 else
1084 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 /* XP does not handle ATTR_POSIX_SEMANTICS */
1086 /* but it helps speed up case sensitive checks for other
1087 servers such as Samba */
1088 if (tcon->ses->capabilities & CAP_UNIX)
1089 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1090
1091 /* if ((omode & S_IWUGO) == 0)
1092 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1093 /* Above line causes problems due to vfs splitting create into two
1094 pieces - need to set mode after file created not while it is
1095 being created */
1096 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1097 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001098 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001099 /* BB Expirement with various impersonation levels and verify */
1100 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 pSMB->SecurityFlags =
1102 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1103
1104 count += name_len;
1105 pSMB->hdr.smb_buf_length += count;
1106
1107 pSMB->ByteCount = cpu_to_le16(count);
1108 /* long_op set to 1 to allow for oplock break timeouts */
1109 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1110 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001111 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 if (rc) {
1113 cFYI(1, ("Error in Open = %d", rc));
1114 } else {
Steve French09d1db52005-04-28 22:41:08 -07001115 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1117 /* Let caller know file was created so we can set the mode. */
1118 /* Do we care about the CreateAction in any other cases? */
1119 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1120 *pOplock |= CIFS_CREATE_ACTION;
1121 if(pfile_info) {
1122 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1123 36 /* CreationTime to Attributes */);
1124 /* the file_info buf is endian converted by caller */
1125 pfile_info->AllocationSize = pSMBr->AllocationSize;
1126 pfile_info->EndOfFile = pSMBr->EndOfFile;
1127 pfile_info->NumberOfLinks = cpu_to_le32(1);
1128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001130
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 cifs_buf_release(pSMB);
1132 if (rc == -EAGAIN)
1133 goto openRetry;
1134 return rc;
1135}
1136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137int
1138CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001139 const int netfid, const unsigned int count,
1140 const __u64 lseek, unsigned int *nbytes, char **buf,
1141 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142{
1143 int rc = -EACCES;
1144 READ_REQ *pSMB = NULL;
1145 READ_RSP *pSMBr = NULL;
1146 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001147 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001148 int resp_buf_type = 0;
1149 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
1151 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001152 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1153 wct = 12;
1154 else
1155 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
1157 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001158 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 if (rc)
1160 return rc;
1161
1162 /* tcon and ses pointer are checked in smb_init */
1163 if (tcon->ses->server == NULL)
1164 return -ECONNABORTED;
1165
Steve Frenchec637e32005-12-12 20:53:18 -08001166 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 pSMB->Fid = netfid;
1168 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001169 if(wct == 12)
1170 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001171 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1172 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001173
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 pSMB->Remaining = 0;
1175 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1176 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001177 if(wct == 12)
1178 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1179 else {
1180 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001181 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001182 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001183 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001184 }
Steve Frenchec637e32005-12-12 20:53:18 -08001185
1186 iov[0].iov_base = (char *)pSMB;
1187 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1188 rc = SendReceive2(xid, tcon->ses, iov,
1189 1 /* num iovecs */,
1190 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001191 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001192 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 if (rc) {
1194 cERROR(1, ("Send error in read = %d", rc));
1195 } else {
1196 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1197 data_length = data_length << 16;
1198 data_length += le16_to_cpu(pSMBr->DataLength);
1199 *nbytes = data_length;
1200
1201 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001202 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 || (data_length > count)) {
1204 cFYI(1,("bad length %d for count %d",data_length,count));
1205 rc = -EIO;
1206 *nbytes = 0;
1207 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001208 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001210/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1211 cERROR(1,("Faulting on read rc = %d",rc));
1212 rc = -EFAULT;
1213 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001215 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 }
1217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Steve French4b8f9302006-02-26 16:41:18 +00001219/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001220 if(*buf) {
1221 if(resp_buf_type == CIFS_SMALL_BUFFER)
1222 cifs_small_buf_release(iov[0].iov_base);
1223 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1224 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001225 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1226 /* return buffer to caller to free */
1227 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001228 if(resp_buf_type == CIFS_SMALL_BUFFER)
1229 *pbuf_type = CIFS_SMALL_BUFFER;
1230 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1231 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001232 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001233
1234 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 since file handle passed in no longer valid */
1236 return rc;
1237}
1238
Steve Frenchec637e32005-12-12 20:53:18 -08001239
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240int
1241CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1242 const int netfid, const unsigned int count,
1243 const __u64 offset, unsigned int *nbytes, const char *buf,
1244 const char __user * ubuf, const int long_op)
1245{
1246 int rc = -EACCES;
1247 WRITE_REQ *pSMB = NULL;
1248 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001249 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 __u32 bytes_sent;
1251 __u16 byte_count;
1252
1253 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001254 if(tcon->ses == NULL)
1255 return -ECONNABORTED;
1256
1257 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1258 wct = 14;
1259 else
1260 wct = 12;
1261
1262 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 (void **) &pSMBr);
1264 if (rc)
1265 return rc;
1266 /* tcon and ses pointer are checked in smb_init */
1267 if (tcon->ses->server == NULL)
1268 return -ECONNABORTED;
1269
1270 pSMB->AndXCommand = 0xFF; /* none */
1271 pSMB->Fid = netfid;
1272 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001273 if(wct == 14)
1274 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1275 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1276 return -EIO;
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 pSMB->Reserved = 0xFFFFFFFF;
1279 pSMB->WriteMode = 0;
1280 pSMB->Remaining = 0;
1281
1282 /* Can increase buffer size if buffer is big enough in some cases - ie we
1283 can send more if LARGE_WRITE_X capability returned by the server and if
1284 our buffer is big enough or if we convert to iovecs on socket writes
1285 and eliminate the copy to the CIFS buffer */
1286 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1287 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1288 } else {
1289 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1290 & ~0xFF;
1291 }
1292
1293 if (bytes_sent > count)
1294 bytes_sent = count;
1295 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001296 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if(buf)
1298 memcpy(pSMB->Data,buf,bytes_sent);
1299 else if(ubuf) {
1300 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1301 cifs_buf_release(pSMB);
1302 return -EFAULT;
1303 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001304 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 /* No buffer */
1306 cifs_buf_release(pSMB);
1307 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001308 } /* else setting file size with write of zero bytes */
1309 if(wct == 14)
1310 byte_count = bytes_sent + 1; /* pad */
1311 else /* wct == 12 */ {
1312 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1315 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001316 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001317
1318 if(wct == 14)
1319 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001320 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001321 struct smb_com_writex_req * pSMBW =
1322 (struct smb_com_writex_req *)pSMB;
1323 pSMBW->ByteCount = cpu_to_le16(byte_count);
1324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
1326 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1327 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001328 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 if (rc) {
1330 cFYI(1, ("Send error in write = %d", rc));
1331 *nbytes = 0;
1332 } else {
1333 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1334 *nbytes = (*nbytes) << 16;
1335 *nbytes += le16_to_cpu(pSMBr->Count);
1336 }
1337
1338 cifs_buf_release(pSMB);
1339
1340 /* Note: On -EAGAIN error only caller can retry on handle based calls
1341 since file handle passed in no longer valid */
1342
1343 return rc;
1344}
1345
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001346int
1347CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001349 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1350 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351{
1352 int rc = -EACCES;
1353 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001354 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001355 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001356 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
Steve Frenchff7feac2005-11-15 16:45:16 -08001358 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1359
Steve French8cc64c62005-10-03 13:49:43 -07001360 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1361 wct = 14;
1362 else
1363 wct = 12;
1364 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 if (rc)
1366 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 /* tcon and ses pointer are checked in smb_init */
1368 if (tcon->ses->server == NULL)
1369 return -ECONNABORTED;
1370
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001371 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 pSMB->Fid = netfid;
1373 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001374 if(wct == 14)
1375 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1376 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1377 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 pSMB->Reserved = 0xFFFFFFFF;
1379 pSMB->WriteMode = 0;
1380 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 pSMB->DataOffset =
1383 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1384
Steve French3e844692005-10-03 13:37:24 -07001385 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1386 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001387 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001388 if(wct == 14)
1389 pSMB->hdr.smb_buf_length += count+1;
1390 else /* wct == 12 */
1391 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1392 if(wct == 14)
1393 pSMB->ByteCount = cpu_to_le16(count + 1);
1394 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1395 struct smb_com_writex_req * pSMBW =
1396 (struct smb_com_writex_req *)pSMB;
1397 pSMBW->ByteCount = cpu_to_le16(count + 5);
1398 }
Steve French3e844692005-10-03 13:37:24 -07001399 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001400 if(wct == 14)
1401 iov[0].iov_len = smb_hdr_len + 4;
1402 else /* wct == 12 pad bigger by four bytes */
1403 iov[0].iov_len = smb_hdr_len + 8;
1404
Steve French3e844692005-10-03 13:37:24 -07001405
Steve Frenchec637e32005-12-12 20:53:18 -08001406 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001407 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001408 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001410 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001412 } else if(resp_buf_type == 0) {
1413 /* presumably this can not happen, but best to be safe */
1414 rc = -EIO;
1415 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001416 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001417 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001418 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1419 *nbytes = (*nbytes) << 16;
1420 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
Steve French4b8f9302006-02-26 16:41:18 +00001423/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001424 if(resp_buf_type == CIFS_SMALL_BUFFER)
1425 cifs_small_buf_release(iov[0].iov_base);
1426 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1427 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428
1429 /* Note: On -EAGAIN error only caller can retry on handle based calls
1430 since file handle passed in no longer valid */
1431
1432 return rc;
1433}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001434
1435
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436int
1437CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1438 const __u16 smb_file_id, const __u64 len,
1439 const __u64 offset, const __u32 numUnlock,
1440 const __u32 numLock, const __u8 lockType, const int waitFlag)
1441{
1442 int rc = 0;
1443 LOCK_REQ *pSMB = NULL;
1444 LOCK_RSP *pSMBr = NULL;
1445 int bytes_returned;
1446 int timeout = 0;
1447 __u16 count;
1448
1449 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001450 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1451
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 if (rc)
1453 return rc;
1454
Steve French46810cb2005-04-28 22:41:09 -07001455 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1456
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1458 timeout = -1; /* no response expected */
1459 pSMB->Timeout = 0;
1460 } else if (waitFlag == TRUE) {
1461 timeout = 3; /* blocking operation, no timeout */
1462 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1463 } else {
1464 pSMB->Timeout = 0;
1465 }
1466
1467 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1468 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1469 pSMB->LockType = lockType;
1470 pSMB->AndXCommand = 0xFF; /* none */
1471 pSMB->Fid = smb_file_id; /* netfid stays le */
1472
1473 if((numLock != 0) || (numUnlock != 0)) {
1474 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1475 /* BB where to store pid high? */
1476 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1477 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1478 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1479 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1480 count = sizeof(LOCKING_ANDX_RANGE);
1481 } else {
1482 /* oplock break */
1483 count = 0;
1484 }
1485 pSMB->hdr.smb_buf_length += count;
1486 pSMB->ByteCount = cpu_to_le16(count);
1487
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001488 if (waitFlag) {
1489 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1490 (struct smb_hdr *) pSMBr, &bytes_returned);
1491 } else {
1492 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001494 }
Steve Frencha4544342005-08-24 13:59:35 -07001495 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 if (rc) {
1497 cFYI(1, ("Send error in Lock = %d", rc));
1498 }
Steve French46810cb2005-04-28 22:41:09 -07001499 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
1501 /* Note: On -EAGAIN error only caller can retry on handle based calls
1502 since file handle passed in no longer valid */
1503 return rc;
1504}
1505
1506int
Steve French08547b02006-02-28 22:39:25 +00001507CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1508 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001509 struct file_lock *pLockData, const __u16 lock_type,
1510 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001511{
1512 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1513 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1514 char *data_offset;
1515 struct cifs_posix_lock *parm_data;
1516 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001517 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001518 int bytes_returned = 0;
1519 __u16 params, param_offset, offset, byte_count, count;
1520
1521 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001522
1523 if(pLockData == NULL)
1524 return EINVAL;
1525
Steve French08547b02006-02-28 22:39:25 +00001526 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1527
1528 if (rc)
1529 return rc;
1530
1531 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1532
1533 params = 6;
1534 pSMB->MaxSetupCount = 0;
1535 pSMB->Reserved = 0;
1536 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001537 pSMB->Reserved2 = 0;
1538 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1539 offset = param_offset + params;
1540
1541 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1542
1543 count = sizeof(struct cifs_posix_lock);
1544 pSMB->MaxParameterCount = cpu_to_le16(2);
1545 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1546 pSMB->SetupCount = 1;
1547 pSMB->Reserved3 = 0;
1548 if(get_flag)
1549 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1550 else
1551 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1552 byte_count = 3 /* pad */ + params + count;
1553 pSMB->DataCount = cpu_to_le16(count);
1554 pSMB->ParameterCount = cpu_to_le16(params);
1555 pSMB->TotalDataCount = pSMB->DataCount;
1556 pSMB->TotalParameterCount = pSMB->ParameterCount;
1557 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1558 parm_data = (struct cifs_posix_lock *)
1559 (((char *) &pSMB->hdr.Protocol) + offset);
1560
1561 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French3a5ff612006-07-14 22:37:11 +00001562 if(waitFlag) {
1563 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001564 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001565 pSMB->Timeout = cpu_to_le32(-1);
1566 } else
1567 pSMB->Timeout = 0;
1568
Steve French08547b02006-02-28 22:39:25 +00001569 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001570 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001571 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001572
1573 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001574 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001575 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1576 pSMB->Reserved4 = 0;
1577 pSMB->hdr.smb_buf_length += byte_count;
1578 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001579 if (waitFlag) {
1580 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1581 (struct smb_hdr *) pSMBr, &bytes_returned);
1582 } else {
1583 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001584 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001585 }
1586
Steve French08547b02006-02-28 22:39:25 +00001587 if (rc) {
1588 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001589 } else if (get_flag) {
1590 /* lock structure can be returned on get */
1591 __u16 data_offset;
1592 __u16 data_count;
1593 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001594
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001595 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1596 rc = -EIO; /* bad smb */
1597 goto plk_err_exit;
1598 }
1599 if(pLockData == NULL) {
1600 rc = -EINVAL;
1601 goto plk_err_exit;
1602 }
1603 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1604 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1605 if(data_count < sizeof(struct cifs_posix_lock)) {
1606 rc = -EIO;
1607 goto plk_err_exit;
1608 }
1609 parm_data = (struct cifs_posix_lock *)
1610 ((char *)&pSMBr->hdr.Protocol + data_offset);
1611 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1612 pLockData->fl_type = F_UNLCK;
1613 }
1614
1615plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001616 if (pSMB)
1617 cifs_small_buf_release(pSMB);
1618
1619 /* Note: On -EAGAIN error only caller can retry on handle based calls
1620 since file handle passed in no longer valid */
1621
1622 return rc;
1623}
1624
1625
1626int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1628{
1629 int rc = 0;
1630 CLOSE_REQ *pSMB = NULL;
1631 CLOSE_RSP *pSMBr = NULL;
1632 int bytes_returned;
1633 cFYI(1, ("In CIFSSMBClose"));
1634
1635/* do not retry on dead session on close */
1636 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1637 if(rc == -EAGAIN)
1638 return 0;
1639 if (rc)
1640 return rc;
1641
1642 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1643
1644 pSMB->FileID = (__u16) smb_file_id;
1645 pSMB->LastWriteTime = 0;
1646 pSMB->ByteCount = 0;
1647 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1648 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001649 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 if (rc) {
1651 if(rc!=-EINTR) {
1652 /* EINTR is expected when user ctl-c to kill app */
1653 cERROR(1, ("Send error in Close = %d", rc));
1654 }
1655 }
1656
1657 cifs_small_buf_release(pSMB);
1658
1659 /* Since session is dead, file will be closed on server already */
1660 if(rc == -EAGAIN)
1661 rc = 0;
1662
1663 return rc;
1664}
1665
1666int
1667CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1668 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001669 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670{
1671 int rc = 0;
1672 RENAME_REQ *pSMB = NULL;
1673 RENAME_RSP *pSMBr = NULL;
1674 int bytes_returned;
1675 int name_len, name_len2;
1676 __u16 count;
1677
1678 cFYI(1, ("In CIFSSMBRename"));
1679renameRetry:
1680 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1681 (void **) &pSMBr);
1682 if (rc)
1683 return rc;
1684
1685 pSMB->BufferFormat = 0x04;
1686 pSMB->SearchAttributes =
1687 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1688 ATTR_DIRECTORY);
1689
1690 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1691 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001692 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001693 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 name_len++; /* trailing null */
1695 name_len *= 2;
1696 pSMB->OldFileName[name_len] = 0x04; /* pad */
1697 /* protocol requires ASCII signature byte on Unicode string */
1698 pSMB->OldFileName[name_len + 1] = 0x00;
1699 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001700 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001701 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1703 name_len2 *= 2; /* convert to bytes */
1704 } else { /* BB improve the check for buffer overruns BB */
1705 name_len = strnlen(fromName, PATH_MAX);
1706 name_len++; /* trailing null */
1707 strncpy(pSMB->OldFileName, fromName, name_len);
1708 name_len2 = strnlen(toName, PATH_MAX);
1709 name_len2++; /* trailing null */
1710 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1711 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1712 name_len2++; /* trailing null */
1713 name_len2++; /* signature byte */
1714 }
1715
1716 count = 1 /* 1st signature byte */ + name_len + name_len2;
1717 pSMB->hdr.smb_buf_length += count;
1718 pSMB->ByteCount = cpu_to_le16(count);
1719
1720 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1721 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001722 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 if (rc) {
1724 cFYI(1, ("Send error in rename = %d", rc));
1725 }
1726
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 cifs_buf_release(pSMB);
1728
1729 if (rc == -EAGAIN)
1730 goto renameRetry;
1731
1732 return rc;
1733}
1734
1735int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001736 int netfid, char * target_name,
1737 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738{
1739 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1740 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1741 struct set_file_rename * rename_info;
1742 char *data_offset;
1743 char dummy_string[30];
1744 int rc = 0;
1745 int bytes_returned = 0;
1746 int len_of_str;
1747 __u16 params, param_offset, offset, count, byte_count;
1748
1749 cFYI(1, ("Rename to File by handle"));
1750 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1751 (void **) &pSMBr);
1752 if (rc)
1753 return rc;
1754
1755 params = 6;
1756 pSMB->MaxSetupCount = 0;
1757 pSMB->Reserved = 0;
1758 pSMB->Flags = 0;
1759 pSMB->Timeout = 0;
1760 pSMB->Reserved2 = 0;
1761 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1762 offset = param_offset + params;
1763
1764 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1765 rename_info = (struct set_file_rename *) data_offset;
1766 pSMB->MaxParameterCount = cpu_to_le16(2);
1767 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1768 pSMB->SetupCount = 1;
1769 pSMB->Reserved3 = 0;
1770 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1771 byte_count = 3 /* pad */ + params;
1772 pSMB->ParameterCount = cpu_to_le16(params);
1773 pSMB->TotalParameterCount = pSMB->ParameterCount;
1774 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1775 pSMB->DataOffset = cpu_to_le16(offset);
1776 /* construct random name ".cifs_tmp<inodenum><mid>" */
1777 rename_info->overwrite = cpu_to_le32(1);
1778 rename_info->root_fid = 0;
1779 /* unicode only call */
1780 if(target_name == NULL) {
1781 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001782 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001783 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001785 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001786 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 }
1788 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1789 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1790 byte_count += count;
1791 pSMB->DataCount = cpu_to_le16(count);
1792 pSMB->TotalDataCount = pSMB->DataCount;
1793 pSMB->Fid = netfid;
1794 pSMB->InformationLevel =
1795 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1796 pSMB->Reserved4 = 0;
1797 pSMB->hdr.smb_buf_length += byte_count;
1798 pSMB->ByteCount = cpu_to_le16(byte_count);
1799 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1800 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001801 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 if (rc) {
1803 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1804 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001805
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 cifs_buf_release(pSMB);
1807
1808 /* Note: On -EAGAIN error only caller can retry on handle based calls
1809 since file handle passed in no longer valid */
1810
1811 return rc;
1812}
1813
1814int
1815CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1816 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001817 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818{
1819 int rc = 0;
1820 COPY_REQ *pSMB = NULL;
1821 COPY_RSP *pSMBr = NULL;
1822 int bytes_returned;
1823 int name_len, name_len2;
1824 __u16 count;
1825
1826 cFYI(1, ("In CIFSSMBCopy"));
1827copyRetry:
1828 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1829 (void **) &pSMBr);
1830 if (rc)
1831 return rc;
1832
1833 pSMB->BufferFormat = 0x04;
1834 pSMB->Tid2 = target_tid;
1835
1836 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1837
1838 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001839 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001840 fromName, PATH_MAX, nls_codepage,
1841 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 name_len++; /* trailing null */
1843 name_len *= 2;
1844 pSMB->OldFileName[name_len] = 0x04; /* pad */
1845 /* protocol requires ASCII signature byte on Unicode string */
1846 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001847 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001848 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1850 name_len2 *= 2; /* convert to bytes */
1851 } else { /* BB improve the check for buffer overruns BB */
1852 name_len = strnlen(fromName, PATH_MAX);
1853 name_len++; /* trailing null */
1854 strncpy(pSMB->OldFileName, fromName, name_len);
1855 name_len2 = strnlen(toName, PATH_MAX);
1856 name_len2++; /* trailing null */
1857 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1858 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1859 name_len2++; /* trailing null */
1860 name_len2++; /* signature byte */
1861 }
1862
1863 count = 1 /* 1st signature byte */ + name_len + name_len2;
1864 pSMB->hdr.smb_buf_length += count;
1865 pSMB->ByteCount = cpu_to_le16(count);
1866
1867 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1868 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1869 if (rc) {
1870 cFYI(1, ("Send error in copy = %d with %d files copied",
1871 rc, le16_to_cpu(pSMBr->CopyCount)));
1872 }
1873 if (pSMB)
1874 cifs_buf_release(pSMB);
1875
1876 if (rc == -EAGAIN)
1877 goto copyRetry;
1878
1879 return rc;
1880}
1881
1882int
1883CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1884 const char *fromName, const char *toName,
1885 const struct nls_table *nls_codepage)
1886{
1887 TRANSACTION2_SPI_REQ *pSMB = NULL;
1888 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1889 char *data_offset;
1890 int name_len;
1891 int name_len_target;
1892 int rc = 0;
1893 int bytes_returned = 0;
1894 __u16 params, param_offset, offset, byte_count;
1895
1896 cFYI(1, ("In Symlink Unix style"));
1897createSymLinkRetry:
1898 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1899 (void **) &pSMBr);
1900 if (rc)
1901 return rc;
1902
1903 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1904 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001905 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 /* find define for this maxpathcomponent */
1907 , nls_codepage);
1908 name_len++; /* trailing null */
1909 name_len *= 2;
1910
1911 } else { /* BB improve the check for buffer overruns BB */
1912 name_len = strnlen(fromName, PATH_MAX);
1913 name_len++; /* trailing null */
1914 strncpy(pSMB->FileName, fromName, name_len);
1915 }
1916 params = 6 + name_len;
1917 pSMB->MaxSetupCount = 0;
1918 pSMB->Reserved = 0;
1919 pSMB->Flags = 0;
1920 pSMB->Timeout = 0;
1921 pSMB->Reserved2 = 0;
1922 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1923 InformationLevel) - 4;
1924 offset = param_offset + params;
1925
1926 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1927 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1928 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001929 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 /* find define for this maxpathcomponent */
1931 , nls_codepage);
1932 name_len_target++; /* trailing null */
1933 name_len_target *= 2;
1934 } else { /* BB improve the check for buffer overruns BB */
1935 name_len_target = strnlen(toName, PATH_MAX);
1936 name_len_target++; /* trailing null */
1937 strncpy(data_offset, toName, name_len_target);
1938 }
1939
1940 pSMB->MaxParameterCount = cpu_to_le16(2);
1941 /* BB find exact max on data count below from sess */
1942 pSMB->MaxDataCount = cpu_to_le16(1000);
1943 pSMB->SetupCount = 1;
1944 pSMB->Reserved3 = 0;
1945 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1946 byte_count = 3 /* pad */ + params + name_len_target;
1947 pSMB->DataCount = cpu_to_le16(name_len_target);
1948 pSMB->ParameterCount = cpu_to_le16(params);
1949 pSMB->TotalDataCount = pSMB->DataCount;
1950 pSMB->TotalParameterCount = pSMB->ParameterCount;
1951 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1952 pSMB->DataOffset = cpu_to_le16(offset);
1953 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1954 pSMB->Reserved4 = 0;
1955 pSMB->hdr.smb_buf_length += byte_count;
1956 pSMB->ByteCount = cpu_to_le16(byte_count);
1957 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1958 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001959 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 if (rc) {
1961 cFYI(1,
1962 ("Send error in SetPathInfo (create symlink) = %d",
1963 rc));
1964 }
1965
1966 if (pSMB)
1967 cifs_buf_release(pSMB);
1968
1969 if (rc == -EAGAIN)
1970 goto createSymLinkRetry;
1971
1972 return rc;
1973}
1974
1975int
1976CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1977 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001978 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979{
1980 TRANSACTION2_SPI_REQ *pSMB = NULL;
1981 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1982 char *data_offset;
1983 int name_len;
1984 int name_len_target;
1985 int rc = 0;
1986 int bytes_returned = 0;
1987 __u16 params, param_offset, offset, byte_count;
1988
1989 cFYI(1, ("In Create Hard link Unix style"));
1990createHardLinkRetry:
1991 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1992 (void **) &pSMBr);
1993 if (rc)
1994 return rc;
1995
1996 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001997 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001998 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 name_len++; /* trailing null */
2000 name_len *= 2;
2001
2002 } else { /* BB improve the check for buffer overruns BB */
2003 name_len = strnlen(toName, PATH_MAX);
2004 name_len++; /* trailing null */
2005 strncpy(pSMB->FileName, toName, name_len);
2006 }
2007 params = 6 + name_len;
2008 pSMB->MaxSetupCount = 0;
2009 pSMB->Reserved = 0;
2010 pSMB->Flags = 0;
2011 pSMB->Timeout = 0;
2012 pSMB->Reserved2 = 0;
2013 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2014 InformationLevel) - 4;
2015 offset = param_offset + params;
2016
2017 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2018 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2019 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002020 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002021 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 name_len_target++; /* trailing null */
2023 name_len_target *= 2;
2024 } else { /* BB improve the check for buffer overruns BB */
2025 name_len_target = strnlen(fromName, PATH_MAX);
2026 name_len_target++; /* trailing null */
2027 strncpy(data_offset, fromName, name_len_target);
2028 }
2029
2030 pSMB->MaxParameterCount = cpu_to_le16(2);
2031 /* BB find exact max on data count below from sess*/
2032 pSMB->MaxDataCount = cpu_to_le16(1000);
2033 pSMB->SetupCount = 1;
2034 pSMB->Reserved3 = 0;
2035 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2036 byte_count = 3 /* pad */ + params + name_len_target;
2037 pSMB->ParameterCount = cpu_to_le16(params);
2038 pSMB->TotalParameterCount = pSMB->ParameterCount;
2039 pSMB->DataCount = cpu_to_le16(name_len_target);
2040 pSMB->TotalDataCount = pSMB->DataCount;
2041 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2042 pSMB->DataOffset = cpu_to_le16(offset);
2043 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2044 pSMB->Reserved4 = 0;
2045 pSMB->hdr.smb_buf_length += byte_count;
2046 pSMB->ByteCount = cpu_to_le16(byte_count);
2047 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2048 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002049 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 if (rc) {
2051 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2052 }
2053
2054 cifs_buf_release(pSMB);
2055 if (rc == -EAGAIN)
2056 goto createHardLinkRetry;
2057
2058 return rc;
2059}
2060
2061int
2062CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2063 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002064 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065{
2066 int rc = 0;
2067 NT_RENAME_REQ *pSMB = NULL;
2068 RENAME_RSP *pSMBr = NULL;
2069 int bytes_returned;
2070 int name_len, name_len2;
2071 __u16 count;
2072
2073 cFYI(1, ("In CIFSCreateHardLink"));
2074winCreateHardLinkRetry:
2075
2076 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2077 (void **) &pSMBr);
2078 if (rc)
2079 return rc;
2080
2081 pSMB->SearchAttributes =
2082 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2083 ATTR_DIRECTORY);
2084 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2085 pSMB->ClusterCount = 0;
2086
2087 pSMB->BufferFormat = 0x04;
2088
2089 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2090 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002091 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002092 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 name_len++; /* trailing null */
2094 name_len *= 2;
2095 pSMB->OldFileName[name_len] = 0; /* pad */
2096 pSMB->OldFileName[name_len + 1] = 0x04;
2097 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002098 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002099 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2101 name_len2 *= 2; /* convert to bytes */
2102 } else { /* BB improve the check for buffer overruns BB */
2103 name_len = strnlen(fromName, PATH_MAX);
2104 name_len++; /* trailing null */
2105 strncpy(pSMB->OldFileName, fromName, name_len);
2106 name_len2 = strnlen(toName, PATH_MAX);
2107 name_len2++; /* trailing null */
2108 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2109 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2110 name_len2++; /* trailing null */
2111 name_len2++; /* signature byte */
2112 }
2113
2114 count = 1 /* string type byte */ + name_len + name_len2;
2115 pSMB->hdr.smb_buf_length += count;
2116 pSMB->ByteCount = cpu_to_le16(count);
2117
2118 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002120 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 if (rc) {
2122 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2123 }
2124 cifs_buf_release(pSMB);
2125 if (rc == -EAGAIN)
2126 goto winCreateHardLinkRetry;
2127
2128 return rc;
2129}
2130
2131int
2132CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2133 const unsigned char *searchName,
2134 char *symlinkinfo, const int buflen,
2135 const struct nls_table *nls_codepage)
2136{
2137/* SMB_QUERY_FILE_UNIX_LINK */
2138 TRANSACTION2_QPI_REQ *pSMB = NULL;
2139 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2140 int rc = 0;
2141 int bytes_returned;
2142 int name_len;
2143 __u16 params, byte_count;
2144
2145 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2146
2147querySymLinkRetry:
2148 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2149 (void **) &pSMBr);
2150 if (rc)
2151 return rc;
2152
2153 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2154 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002155 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 /* find define for this maxpathcomponent */
2157 , nls_codepage);
2158 name_len++; /* trailing null */
2159 name_len *= 2;
2160 } else { /* BB improve the check for buffer overruns BB */
2161 name_len = strnlen(searchName, PATH_MAX);
2162 name_len++; /* trailing null */
2163 strncpy(pSMB->FileName, searchName, name_len);
2164 }
2165
2166 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2167 pSMB->TotalDataCount = 0;
2168 pSMB->MaxParameterCount = cpu_to_le16(2);
2169 /* BB find exact max data count below from sess structure BB */
2170 pSMB->MaxDataCount = cpu_to_le16(4000);
2171 pSMB->MaxSetupCount = 0;
2172 pSMB->Reserved = 0;
2173 pSMB->Flags = 0;
2174 pSMB->Timeout = 0;
2175 pSMB->Reserved2 = 0;
2176 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2177 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2178 pSMB->DataCount = 0;
2179 pSMB->DataOffset = 0;
2180 pSMB->SetupCount = 1;
2181 pSMB->Reserved3 = 0;
2182 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2183 byte_count = params + 1 /* pad */ ;
2184 pSMB->TotalParameterCount = cpu_to_le16(params);
2185 pSMB->ParameterCount = pSMB->TotalParameterCount;
2186 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2187 pSMB->Reserved4 = 0;
2188 pSMB->hdr.smb_buf_length += byte_count;
2189 pSMB->ByteCount = cpu_to_le16(byte_count);
2190
2191 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2192 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2193 if (rc) {
2194 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2195 } else {
2196 /* decode response */
2197
2198 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2199 if (rc || (pSMBr->ByteCount < 2))
2200 /* BB also check enough total bytes returned */
2201 rc = -EIO; /* bad smb */
2202 else {
2203 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2204 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2205
2206 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2207 name_len = UniStrnlen((wchar_t *) ((char *)
2208 &pSMBr->hdr.Protocol +data_offset),
2209 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002210 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002212 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 data_offset),
2214 name_len, nls_codepage);
2215 } else {
2216 strncpy(symlinkinfo,
2217 (char *) &pSMBr->hdr.Protocol +
2218 data_offset,
2219 min_t(const int, buflen, count));
2220 }
2221 symlinkinfo[buflen] = 0;
2222 /* just in case so calling code does not go off the end of buffer */
2223 }
2224 }
2225 cifs_buf_release(pSMB);
2226 if (rc == -EAGAIN)
2227 goto querySymLinkRetry;
2228 return rc;
2229}
2230
Steve French0a4b92c2006-01-12 15:44:21 -08002231/* Initialize NT TRANSACT SMB into small smb request buffer.
2232 This assumes that all NT TRANSACTS that we init here have
2233 total parm and data under about 400 bytes (to fit in small cifs
2234 buffer size), which is the case so far, it easily fits. NB:
2235 Setup words themselves and ByteCount
2236 MaxSetupCount (size of returned setup area) and
2237 MaxParameterCount (returned parms size) must be set by caller */
2238static int
2239smb_init_ntransact(const __u16 sub_command, const int setup_count,
2240 const int parm_len, struct cifsTconInfo *tcon,
2241 void ** ret_buf)
2242{
2243 int rc;
2244 __u32 temp_offset;
2245 struct smb_com_ntransact_req * pSMB;
2246
2247 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2248 (void **)&pSMB);
2249 if (rc)
2250 return rc;
2251 *ret_buf = (void *)pSMB;
2252 pSMB->Reserved = 0;
2253 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2254 pSMB->TotalDataCount = 0;
2255 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2256 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2257 pSMB->ParameterCount = pSMB->TotalParameterCount;
2258 pSMB->DataCount = pSMB->TotalDataCount;
2259 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2260 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2261 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2262 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2263 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2264 pSMB->SubCommand = cpu_to_le16(sub_command);
2265 return 0;
2266}
2267
2268static int
2269validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2270 int * pdatalen, int * pparmlen)
2271{
2272 char * end_of_smb;
2273 __u32 data_count, data_offset, parm_count, parm_offset;
2274 struct smb_com_ntransact_rsp * pSMBr;
2275
2276 if(buf == NULL)
2277 return -EINVAL;
2278
2279 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2280
2281 /* ByteCount was converted from little endian in SendReceive */
2282 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2283 (char *)&pSMBr->ByteCount;
2284
2285
2286 data_offset = le32_to_cpu(pSMBr->DataOffset);
2287 data_count = le32_to_cpu(pSMBr->DataCount);
2288 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2289 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2290
2291 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2292 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2293
2294 /* should we also check that parm and data areas do not overlap? */
2295 if(*ppparm > end_of_smb) {
2296 cFYI(1,("parms start after end of smb"));
2297 return -EINVAL;
2298 } else if(parm_count + *ppparm > end_of_smb) {
2299 cFYI(1,("parm end after end of smb"));
2300 return -EINVAL;
2301 } else if(*ppdata > end_of_smb) {
2302 cFYI(1,("data starts after end of smb"));
2303 return -EINVAL;
2304 } else if(data_count + *ppdata > end_of_smb) {
2305 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2306 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2307 return -EINVAL;
2308 } else if(parm_count + data_count > pSMBr->ByteCount) {
2309 cFYI(1,("parm count and data count larger than SMB"));
2310 return -EINVAL;
2311 }
2312 return 0;
2313}
2314
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315int
2316CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2317 const unsigned char *searchName,
2318 char *symlinkinfo, const int buflen,__u16 fid,
2319 const struct nls_table *nls_codepage)
2320{
2321 int rc = 0;
2322 int bytes_returned;
2323 int name_len;
2324 struct smb_com_transaction_ioctl_req * pSMB;
2325 struct smb_com_transaction_ioctl_rsp * pSMBr;
2326
2327 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2328 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2329 (void **) &pSMBr);
2330 if (rc)
2331 return rc;
2332
2333 pSMB->TotalParameterCount = 0 ;
2334 pSMB->TotalDataCount = 0;
2335 pSMB->MaxParameterCount = cpu_to_le32(2);
2336 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002337 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2338 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 pSMB->MaxSetupCount = 4;
2340 pSMB->Reserved = 0;
2341 pSMB->ParameterOffset = 0;
2342 pSMB->DataCount = 0;
2343 pSMB->DataOffset = 0;
2344 pSMB->SetupCount = 4;
2345 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2346 pSMB->ParameterCount = pSMB->TotalParameterCount;
2347 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2348 pSMB->IsFsctl = 1; /* FSCTL */
2349 pSMB->IsRootFlag = 0;
2350 pSMB->Fid = fid; /* file handle always le */
2351 pSMB->ByteCount = 0;
2352
2353 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2354 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2355 if (rc) {
2356 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2357 } else { /* decode response */
2358 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2359 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2360 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2361 /* BB also check enough total bytes returned */
2362 rc = -EIO; /* bad smb */
2363 else {
2364 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002365 char * end_of_smb = 2 /* sizeof byte count */ +
2366 pSMBr->ByteCount +
2367 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
2369 struct reparse_data * reparse_buf = (struct reparse_data *)
2370 ((char *)&pSMBr->hdr.Protocol + data_offset);
2371 if((char*)reparse_buf >= end_of_smb) {
2372 rc = -EIO;
2373 goto qreparse_out;
2374 }
2375 if((reparse_buf->LinkNamesBuf +
2376 reparse_buf->TargetNameOffset +
2377 reparse_buf->TargetNameLen) >
2378 end_of_smb) {
2379 cFYI(1,("reparse buf extended beyond SMB"));
2380 rc = -EIO;
2381 goto qreparse_out;
2382 }
2383
2384 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2385 name_len = UniStrnlen((wchar_t *)
2386 (reparse_buf->LinkNamesBuf +
2387 reparse_buf->TargetNameOffset),
2388 min(buflen/2, reparse_buf->TargetNameLen / 2));
2389 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002390 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 reparse_buf->TargetNameOffset),
2392 name_len, nls_codepage);
2393 } else { /* ASCII names */
2394 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2395 reparse_buf->TargetNameOffset,
2396 min_t(const int, buflen, reparse_buf->TargetNameLen));
2397 }
2398 } else {
2399 rc = -EIO;
2400 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2401 }
2402 symlinkinfo[buflen] = 0; /* just in case so the caller
2403 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002404 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 }
2406 }
2407qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002408 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
2410 /* Note: On -EAGAIN error only caller can retry on handle based calls
2411 since file handle passed in no longer valid */
2412
2413 return rc;
2414}
2415
2416#ifdef CONFIG_CIFS_POSIX
2417
2418/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2419static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2420{
2421 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002422 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2423 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2424 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2426
2427 return;
2428}
2429
2430/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002431static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2432 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433{
2434 int size = 0;
2435 int i;
2436 __u16 count;
2437 struct cifs_posix_ace * pACE;
2438 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2439 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2440
2441 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2442 return -EOPNOTSUPP;
2443
2444 if(acl_type & ACL_TYPE_ACCESS) {
2445 count = le16_to_cpu(cifs_acl->access_entry_count);
2446 pACE = &cifs_acl->ace_array[0];
2447 size = sizeof(struct cifs_posix_acl);
2448 size += sizeof(struct cifs_posix_ace) * count;
2449 /* check if we would go beyond end of SMB */
2450 if(size_of_data_area < size) {
2451 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2452 return -EINVAL;
2453 }
2454 } else if(acl_type & ACL_TYPE_DEFAULT) {
2455 count = le16_to_cpu(cifs_acl->access_entry_count);
2456 size = sizeof(struct cifs_posix_acl);
2457 size += sizeof(struct cifs_posix_ace) * count;
2458/* skip past access ACEs to get to default ACEs */
2459 pACE = &cifs_acl->ace_array[count];
2460 count = le16_to_cpu(cifs_acl->default_entry_count);
2461 size += sizeof(struct cifs_posix_ace) * count;
2462 /* check if we would go beyond end of SMB */
2463 if(size_of_data_area < size)
2464 return -EINVAL;
2465 } else {
2466 /* illegal type */
2467 return -EINVAL;
2468 }
2469
2470 size = posix_acl_xattr_size(count);
2471 if((buflen == 0) || (local_acl == NULL)) {
2472 /* used to query ACL EA size */
2473 } else if(size > buflen) {
2474 return -ERANGE;
2475 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002476 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 for(i = 0;i < count ;i++) {
2478 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2479 pACE ++;
2480 }
2481 }
2482 return size;
2483}
2484
2485static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2486 const posix_acl_xattr_entry * local_ace)
2487{
2488 __u16 rc = 0; /* 0 = ACL converted ok */
2489
Steve Frenchff7feac2005-11-15 16:45:16 -08002490 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2491 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002493 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 /* Probably no need to le convert -1 on any arch but can not hurt */
2495 cifs_ace->cifs_uid = cpu_to_le64(-1);
2496 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002497 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2499 return rc;
2500}
2501
2502/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2503static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2504 const int acl_type)
2505{
2506 __u16 rc = 0;
2507 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2508 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2509 int count;
2510 int i;
2511
2512 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2513 return 0;
2514
2515 count = posix_acl_xattr_count((size_t)buflen);
2516 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002517 count, buflen, le32_to_cpu(local_acl->a_version)));
2518 if(le32_to_cpu(local_acl->a_version) != 2) {
2519 cFYI(1,("unknown POSIX ACL version %d",
2520 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 return 0;
2522 }
2523 cifs_acl->version = cpu_to_le16(1);
2524 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002525 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002527 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 else {
2529 cFYI(1,("unknown ACL type %d",acl_type));
2530 return 0;
2531 }
2532 for(i=0;i<count;i++) {
2533 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2534 &local_acl->a_entries[i]);
2535 if(rc != 0) {
2536 /* ACE not converted */
2537 break;
2538 }
2539 }
2540 if(rc == 0) {
2541 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2542 rc += sizeof(struct cifs_posix_acl);
2543 /* BB add check to make sure ACL does not overflow SMB */
2544 }
2545 return rc;
2546}
2547
2548int
2549CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2550 const unsigned char *searchName,
2551 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002552 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553{
2554/* SMB_QUERY_POSIX_ACL */
2555 TRANSACTION2_QPI_REQ *pSMB = NULL;
2556 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2557 int rc = 0;
2558 int bytes_returned;
2559 int name_len;
2560 __u16 params, byte_count;
2561
2562 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2563
2564queryAclRetry:
2565 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2566 (void **) &pSMBr);
2567 if (rc)
2568 return rc;
2569
2570 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2571 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002572 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002573 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 name_len++; /* trailing null */
2575 name_len *= 2;
2576 pSMB->FileName[name_len] = 0;
2577 pSMB->FileName[name_len+1] = 0;
2578 } else { /* BB improve the check for buffer overruns BB */
2579 name_len = strnlen(searchName, PATH_MAX);
2580 name_len++; /* trailing null */
2581 strncpy(pSMB->FileName, searchName, name_len);
2582 }
2583
2584 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2585 pSMB->TotalDataCount = 0;
2586 pSMB->MaxParameterCount = cpu_to_le16(2);
2587 /* BB find exact max data count below from sess structure BB */
2588 pSMB->MaxDataCount = cpu_to_le16(4000);
2589 pSMB->MaxSetupCount = 0;
2590 pSMB->Reserved = 0;
2591 pSMB->Flags = 0;
2592 pSMB->Timeout = 0;
2593 pSMB->Reserved2 = 0;
2594 pSMB->ParameterOffset = cpu_to_le16(
2595 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2596 pSMB->DataCount = 0;
2597 pSMB->DataOffset = 0;
2598 pSMB->SetupCount = 1;
2599 pSMB->Reserved3 = 0;
2600 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2601 byte_count = params + 1 /* pad */ ;
2602 pSMB->TotalParameterCount = cpu_to_le16(params);
2603 pSMB->ParameterCount = pSMB->TotalParameterCount;
2604 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2605 pSMB->Reserved4 = 0;
2606 pSMB->hdr.smb_buf_length += byte_count;
2607 pSMB->ByteCount = cpu_to_le16(byte_count);
2608
2609 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2610 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002611 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 if (rc) {
2613 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2614 } else {
2615 /* decode response */
2616
2617 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2618 if (rc || (pSMBr->ByteCount < 2))
2619 /* BB also check enough total bytes returned */
2620 rc = -EIO; /* bad smb */
2621 else {
2622 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2623 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2624 rc = cifs_copy_posix_acl(acl_inf,
2625 (char *)&pSMBr->hdr.Protocol+data_offset,
2626 buflen,acl_type,count);
2627 }
2628 }
2629 cifs_buf_release(pSMB);
2630 if (rc == -EAGAIN)
2631 goto queryAclRetry;
2632 return rc;
2633}
2634
2635int
2636CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2637 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002638 const char *local_acl, const int buflen,
2639 const int acl_type,
2640 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641{
2642 struct smb_com_transaction2_spi_req *pSMB = NULL;
2643 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2644 char *parm_data;
2645 int name_len;
2646 int rc = 0;
2647 int bytes_returned = 0;
2648 __u16 params, byte_count, data_count, param_offset, offset;
2649
2650 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2651setAclRetry:
2652 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2653 (void **) &pSMBr);
2654 if (rc)
2655 return rc;
2656 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2657 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002658 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002659 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 name_len++; /* trailing null */
2661 name_len *= 2;
2662 } else { /* BB improve the check for buffer overruns BB */
2663 name_len = strnlen(fileName, PATH_MAX);
2664 name_len++; /* trailing null */
2665 strncpy(pSMB->FileName, fileName, name_len);
2666 }
2667 params = 6 + name_len;
2668 pSMB->MaxParameterCount = cpu_to_le16(2);
2669 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2670 pSMB->MaxSetupCount = 0;
2671 pSMB->Reserved = 0;
2672 pSMB->Flags = 0;
2673 pSMB->Timeout = 0;
2674 pSMB->Reserved2 = 0;
2675 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2676 InformationLevel) - 4;
2677 offset = param_offset + params;
2678 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2679 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2680
2681 /* convert to on the wire format for POSIX ACL */
2682 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2683
2684 if(data_count == 0) {
2685 rc = -EOPNOTSUPP;
2686 goto setACLerrorExit;
2687 }
2688 pSMB->DataOffset = cpu_to_le16(offset);
2689 pSMB->SetupCount = 1;
2690 pSMB->Reserved3 = 0;
2691 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2692 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2693 byte_count = 3 /* pad */ + params + data_count;
2694 pSMB->DataCount = cpu_to_le16(data_count);
2695 pSMB->TotalDataCount = pSMB->DataCount;
2696 pSMB->ParameterCount = cpu_to_le16(params);
2697 pSMB->TotalParameterCount = pSMB->ParameterCount;
2698 pSMB->Reserved4 = 0;
2699 pSMB->hdr.smb_buf_length += byte_count;
2700 pSMB->ByteCount = cpu_to_le16(byte_count);
2701 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2702 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2703 if (rc) {
2704 cFYI(1, ("Set POSIX ACL returned %d", rc));
2705 }
2706
2707setACLerrorExit:
2708 cifs_buf_release(pSMB);
2709 if (rc == -EAGAIN)
2710 goto setAclRetry;
2711 return rc;
2712}
2713
Steve Frenchf654bac2005-04-28 22:41:04 -07002714/* BB fix tabs in this function FIXME BB */
2715int
2716CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2717 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2718{
2719 int rc = 0;
2720 struct smb_t2_qfi_req *pSMB = NULL;
2721 struct smb_t2_qfi_rsp *pSMBr = NULL;
2722 int bytes_returned;
2723 __u16 params, byte_count;
2724
2725 cFYI(1,("In GetExtAttr"));
2726 if(tcon == NULL)
2727 return -ENODEV;
2728
2729GetExtAttrRetry:
2730 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2731 (void **) &pSMBr);
2732 if (rc)
2733 return rc;
2734
Steve Frenchc67593a2005-04-28 22:41:04 -07002735 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002736 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002737 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002738 /* BB find exact max data count below from sess structure BB */
2739 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2740 pSMB->t2.MaxSetupCount = 0;
2741 pSMB->t2.Reserved = 0;
2742 pSMB->t2.Flags = 0;
2743 pSMB->t2.Timeout = 0;
2744 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002745 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2746 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002747 pSMB->t2.DataCount = 0;
2748 pSMB->t2.DataOffset = 0;
2749 pSMB->t2.SetupCount = 1;
2750 pSMB->t2.Reserved3 = 0;
2751 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002752 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002753 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2754 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2755 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002756 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002757 pSMB->Fid = netfid;
2758 pSMB->hdr.smb_buf_length += byte_count;
2759 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2760
2761 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2762 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2763 if (rc) {
2764 cFYI(1, ("error %d in GetExtAttr", rc));
2765 } else {
2766 /* decode response */
2767 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2768 if (rc || (pSMBr->ByteCount < 2))
2769 /* BB also check enough total bytes returned */
2770 /* If rc should we check for EOPNOSUPP and
2771 disable the srvino flag? or in caller? */
2772 rc = -EIO; /* bad smb */
2773 else {
2774 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2775 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2776 struct file_chattr_info * pfinfo;
2777 /* BB Do we need a cast or hash here ? */
2778 if(count != 16) {
2779 cFYI(1, ("Illegal size ret in GetExtAttr"));
2780 rc = -EIO;
2781 goto GetExtAttrOut;
2782 }
2783 pfinfo = (struct file_chattr_info *)
2784 (data_offset + (char *) &pSMBr->hdr.Protocol);
2785 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2786 *pMask = le64_to_cpu(pfinfo->mask);
2787 }
2788 }
2789GetExtAttrOut:
2790 cifs_buf_release(pSMB);
2791 if (rc == -EAGAIN)
2792 goto GetExtAttrRetry;
2793 return rc;
2794}
2795
2796
2797#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
Steve Frencheeac8042006-01-13 21:34:58 -08002799
2800/* security id for everyone */
Steve French2cd646a2006-09-28 19:43:08 +00002801const static struct cifs_sid sid_everyone =
2802 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002803/* group users */
Steve French2cd646a2006-09-28 19:43:08 +00002804const static struct cifs_sid sid_user =
2805 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002806
Steve French0a4b92c2006-01-12 15:44:21 -08002807/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002808static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002809{
Steve French0a4b92c2006-01-12 15:44:21 -08002810 return 0;
2811}
2812
2813/* Get Security Descriptor (by handle) from remote server for a file or dir */
2814int
2815CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2816 /* BB fix up return info */ char *acl_inf, const int buflen,
2817 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2818{
2819 int rc = 0;
2820 int buf_type = 0;
2821 QUERY_SEC_DESC_REQ * pSMB;
2822 struct kvec iov[1];
2823
2824 cFYI(1, ("GetCifsACL"));
2825
2826 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2827 8 /* parm len */, tcon, (void **) &pSMB);
2828 if (rc)
2829 return rc;
2830
2831 pSMB->MaxParameterCount = cpu_to_le32(4);
2832 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2833 pSMB->MaxSetupCount = 0;
2834 pSMB->Fid = fid; /* file handle always le */
2835 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2836 CIFS_ACL_DACL);
2837 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2838 pSMB->hdr.smb_buf_length += 11;
2839 iov[0].iov_base = (char *)pSMB;
2840 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2841
2842 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2843 cifs_stats_inc(&tcon->num_acl_get);
2844 if (rc) {
2845 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2846 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002847 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002848 __le32 * parm;
2849 int parm_len;
2850 int data_len;
2851 int acl_len;
2852 struct smb_com_ntransact_rsp * pSMBr;
2853
2854/* validate_nttransact */
2855 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2856 (char **)&psec_desc,
2857 &parm_len, &data_len);
2858
2859 if(rc)
2860 goto qsec_out;
2861 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2862
2863 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2864
2865 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2866 rc = -EIO; /* bad smb */
2867 goto qsec_out;
2868 }
2869
2870/* BB check that data area is minimum length and as big as acl_len */
2871
2872 acl_len = le32_to_cpu(*(__le32 *)parm);
2873 /* BB check if(acl_len > bufsize) */
2874
2875 parse_sec_desc(psec_desc, acl_len);
2876 }
2877qsec_out:
2878 if(buf_type == CIFS_SMALL_BUFFER)
2879 cifs_small_buf_release(iov[0].iov_base);
2880 else if(buf_type == CIFS_LARGE_BUFFER)
2881 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002882/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002883 return rc;
2884}
2885
Steve French6b8edfe2005-08-23 20:26:03 -07002886/* Legacy Query Path Information call for lookup to old servers such
2887 as Win9x/WinME */
2888int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2889 const unsigned char *searchName,
2890 FILE_ALL_INFO * pFinfo,
2891 const struct nls_table *nls_codepage, int remap)
2892{
2893 QUERY_INFORMATION_REQ * pSMB;
2894 QUERY_INFORMATION_RSP * pSMBr;
2895 int rc = 0;
2896 int bytes_returned;
2897 int name_len;
2898
2899 cFYI(1, ("In SMBQPath path %s", searchName));
2900QInfRetry:
2901 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2902 (void **) &pSMBr);
2903 if (rc)
2904 return rc;
2905
2906 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2907 name_len =
2908 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2909 PATH_MAX, nls_codepage, remap);
2910 name_len++; /* trailing null */
2911 name_len *= 2;
2912 } else {
2913 name_len = strnlen(searchName, PATH_MAX);
2914 name_len++; /* trailing null */
2915 strncpy(pSMB->FileName, searchName, name_len);
2916 }
2917 pSMB->BufferFormat = 0x04;
2918 name_len++; /* account for buffer type byte */
2919 pSMB->hdr.smb_buf_length += (__u16) name_len;
2920 pSMB->ByteCount = cpu_to_le16(name_len);
2921
2922 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2923 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2924 if (rc) {
2925 cFYI(1, ("Send error in QueryInfo = %d", rc));
2926 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00002927 struct timespec ts;
2928 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2929 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07002930 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00002931 ts.tv_nsec = 0;
2932 ts.tv_sec = time;
2933 /* decode time fields */
2934 pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
2935 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2936 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07002937 pFinfo->AllocationSize =
2938 cpu_to_le64(le32_to_cpu(pSMBr->size));
2939 pFinfo->EndOfFile = pFinfo->AllocationSize;
2940 pFinfo->Attributes =
2941 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002942 } else
2943 rc = -EIO; /* bad buffer passed in */
2944
2945 cifs_buf_release(pSMB);
2946
2947 if (rc == -EAGAIN)
2948 goto QInfRetry;
2949
2950 return rc;
2951}
2952
2953
2954
2955
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956int
2957CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2958 const unsigned char *searchName,
2959 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002960 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961{
2962/* level 263 SMB_QUERY_FILE_ALL_INFO */
2963 TRANSACTION2_QPI_REQ *pSMB = NULL;
2964 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2965 int rc = 0;
2966 int bytes_returned;
2967 int name_len;
2968 __u16 params, byte_count;
2969
2970/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2971QPathInfoRetry:
2972 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2973 (void **) &pSMBr);
2974 if (rc)
2975 return rc;
2976
2977 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2978 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002979 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002980 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 name_len++; /* trailing null */
2982 name_len *= 2;
2983 } else { /* BB improve the check for buffer overruns BB */
2984 name_len = strnlen(searchName, PATH_MAX);
2985 name_len++; /* trailing null */
2986 strncpy(pSMB->FileName, searchName, name_len);
2987 }
2988
2989 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2990 pSMB->TotalDataCount = 0;
2991 pSMB->MaxParameterCount = cpu_to_le16(2);
2992 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2993 pSMB->MaxSetupCount = 0;
2994 pSMB->Reserved = 0;
2995 pSMB->Flags = 0;
2996 pSMB->Timeout = 0;
2997 pSMB->Reserved2 = 0;
2998 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2999 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3000 pSMB->DataCount = 0;
3001 pSMB->DataOffset = 0;
3002 pSMB->SetupCount = 1;
3003 pSMB->Reserved3 = 0;
3004 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3005 byte_count = params + 1 /* pad */ ;
3006 pSMB->TotalParameterCount = cpu_to_le16(params);
3007 pSMB->ParameterCount = pSMB->TotalParameterCount;
3008 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3009 pSMB->Reserved4 = 0;
3010 pSMB->hdr.smb_buf_length += byte_count;
3011 pSMB->ByteCount = cpu_to_le16(byte_count);
3012
3013 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3014 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3015 if (rc) {
3016 cFYI(1, ("Send error in QPathInfo = %d", rc));
3017 } else { /* decode response */
3018 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3019
3020 if (rc || (pSMBr->ByteCount < 40))
3021 rc = -EIO; /* bad smb */
3022 else if (pFindData){
3023 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3024 memcpy((char *) pFindData,
3025 (char *) &pSMBr->hdr.Protocol +
3026 data_offset, sizeof (FILE_ALL_INFO));
3027 } else
3028 rc = -ENOMEM;
3029 }
3030 cifs_buf_release(pSMB);
3031 if (rc == -EAGAIN)
3032 goto QPathInfoRetry;
3033
3034 return rc;
3035}
3036
3037int
3038CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3039 const unsigned char *searchName,
3040 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003041 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042{
3043/* SMB_QUERY_FILE_UNIX_BASIC */
3044 TRANSACTION2_QPI_REQ *pSMB = NULL;
3045 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3046 int rc = 0;
3047 int bytes_returned = 0;
3048 int name_len;
3049 __u16 params, byte_count;
3050
3051 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3052UnixQPathInfoRetry:
3053 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3054 (void **) &pSMBr);
3055 if (rc)
3056 return rc;
3057
3058 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3059 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003060 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003061 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 name_len++; /* trailing null */
3063 name_len *= 2;
3064 } else { /* BB improve the check for buffer overruns BB */
3065 name_len = strnlen(searchName, PATH_MAX);
3066 name_len++; /* trailing null */
3067 strncpy(pSMB->FileName, searchName, name_len);
3068 }
3069
3070 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3071 pSMB->TotalDataCount = 0;
3072 pSMB->MaxParameterCount = cpu_to_le16(2);
3073 /* BB find exact max SMB PDU from sess structure BB */
3074 pSMB->MaxDataCount = cpu_to_le16(4000);
3075 pSMB->MaxSetupCount = 0;
3076 pSMB->Reserved = 0;
3077 pSMB->Flags = 0;
3078 pSMB->Timeout = 0;
3079 pSMB->Reserved2 = 0;
3080 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3081 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3082 pSMB->DataCount = 0;
3083 pSMB->DataOffset = 0;
3084 pSMB->SetupCount = 1;
3085 pSMB->Reserved3 = 0;
3086 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3087 byte_count = params + 1 /* pad */ ;
3088 pSMB->TotalParameterCount = cpu_to_le16(params);
3089 pSMB->ParameterCount = pSMB->TotalParameterCount;
3090 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3091 pSMB->Reserved4 = 0;
3092 pSMB->hdr.smb_buf_length += byte_count;
3093 pSMB->ByteCount = cpu_to_le16(byte_count);
3094
3095 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3096 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3097 if (rc) {
3098 cFYI(1, ("Send error in QPathInfo = %d", rc));
3099 } else { /* decode response */
3100 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3101
3102 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3103 rc = -EIO; /* bad smb */
3104 } else {
3105 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3106 memcpy((char *) pFindData,
3107 (char *) &pSMBr->hdr.Protocol +
3108 data_offset,
3109 sizeof (FILE_UNIX_BASIC_INFO));
3110 }
3111 }
3112 cifs_buf_release(pSMB);
3113 if (rc == -EAGAIN)
3114 goto UnixQPathInfoRetry;
3115
3116 return rc;
3117}
3118
3119#if 0 /* function unused at present */
3120int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3121 const char *searchName, FILE_ALL_INFO * findData,
3122 const struct nls_table *nls_codepage)
3123{
3124/* level 257 SMB_ */
3125 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3126 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3127 int rc = 0;
3128 int bytes_returned;
3129 int name_len;
3130 __u16 params, byte_count;
3131
3132 cFYI(1, ("In FindUnique"));
3133findUniqueRetry:
3134 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3135 (void **) &pSMBr);
3136 if (rc)
3137 return rc;
3138
3139 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3140 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003141 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 /* find define for this maxpathcomponent */
3143 , nls_codepage);
3144 name_len++; /* trailing null */
3145 name_len *= 2;
3146 } else { /* BB improve the check for buffer overruns BB */
3147 name_len = strnlen(searchName, PATH_MAX);
3148 name_len++; /* trailing null */
3149 strncpy(pSMB->FileName, searchName, name_len);
3150 }
3151
3152 params = 12 + name_len /* includes null */ ;
3153 pSMB->TotalDataCount = 0; /* no EAs */
3154 pSMB->MaxParameterCount = cpu_to_le16(2);
3155 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3156 pSMB->MaxSetupCount = 0;
3157 pSMB->Reserved = 0;
3158 pSMB->Flags = 0;
3159 pSMB->Timeout = 0;
3160 pSMB->Reserved2 = 0;
3161 pSMB->ParameterOffset = cpu_to_le16(
3162 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3163 pSMB->DataCount = 0;
3164 pSMB->DataOffset = 0;
3165 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3166 pSMB->Reserved3 = 0;
3167 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3168 byte_count = params + 1 /* pad */ ;
3169 pSMB->TotalParameterCount = cpu_to_le16(params);
3170 pSMB->ParameterCount = pSMB->TotalParameterCount;
3171 pSMB->SearchAttributes =
3172 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3173 ATTR_DIRECTORY);
3174 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3175 pSMB->SearchFlags = cpu_to_le16(1);
3176 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3177 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3178 pSMB->hdr.smb_buf_length += byte_count;
3179 pSMB->ByteCount = cpu_to_le16(byte_count);
3180
3181 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3182 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3183
3184 if (rc) {
3185 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3186 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003187 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 /* BB fill in */
3189 }
3190
3191 cifs_buf_release(pSMB);
3192 if (rc == -EAGAIN)
3193 goto findUniqueRetry;
3194
3195 return rc;
3196}
3197#endif /* end unused (temporarily) function */
3198
3199/* xid, tcon, searchName and codepage are input parms, rest are returned */
3200int
3201CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3202 const char *searchName,
3203 const struct nls_table *nls_codepage,
3204 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003205 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206{
3207/* level 257 SMB_ */
3208 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3209 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3210 T2_FFIRST_RSP_PARMS * parms;
3211 int rc = 0;
3212 int bytes_returned = 0;
3213 int name_len;
3214 __u16 params, byte_count;
3215
Steve French737b7582005-04-28 22:41:06 -07003216 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
3218findFirstRetry:
3219 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3220 (void **) &pSMBr);
3221 if (rc)
3222 return rc;
3223
3224 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3225 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003226 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003227 PATH_MAX, nls_codepage, remap);
3228 /* We can not add the asterik earlier in case
3229 it got remapped to 0xF03A as if it were part of the
3230 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003232 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003233 pSMB->FileName[name_len+1] = 0;
3234 pSMB->FileName[name_len+2] = '*';
3235 pSMB->FileName[name_len+3] = 0;
3236 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3238 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003239 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 } else { /* BB add check for overrun of SMB buf BB */
3241 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242/* BB fix here and in unicode clause above ie
3243 if(name_len > buffersize-header)
3244 free buffer exit; BB */
3245 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003246 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003247 pSMB->FileName[name_len+1] = '*';
3248 pSMB->FileName[name_len+2] = 0;
3249 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 }
3251
3252 params = 12 + name_len /* includes null */ ;
3253 pSMB->TotalDataCount = 0; /* no EAs */
3254 pSMB->MaxParameterCount = cpu_to_le16(10);
3255 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3256 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3257 pSMB->MaxSetupCount = 0;
3258 pSMB->Reserved = 0;
3259 pSMB->Flags = 0;
3260 pSMB->Timeout = 0;
3261 pSMB->Reserved2 = 0;
3262 byte_count = params + 1 /* pad */ ;
3263 pSMB->TotalParameterCount = cpu_to_le16(params);
3264 pSMB->ParameterCount = pSMB->TotalParameterCount;
3265 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003266 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3267 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 pSMB->DataCount = 0;
3269 pSMB->DataOffset = 0;
3270 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3271 pSMB->Reserved3 = 0;
3272 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3273 pSMB->SearchAttributes =
3274 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3275 ATTR_DIRECTORY);
3276 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3277 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3278 CIFS_SEARCH_RETURN_RESUME);
3279 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3280
3281 /* BB what should we set StorageType to? Does it matter? BB */
3282 pSMB->SearchStorageType = 0;
3283 pSMB->hdr.smb_buf_length += byte_count;
3284 pSMB->ByteCount = cpu_to_le16(byte_count);
3285
3286 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3287 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003288 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289
Steve French88274812006-03-09 22:21:45 +00003290 if (rc) {/* BB add logic to retry regular search if Unix search
3291 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 /* BB Add code to handle unsupported level rc */
3293 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003294
Steve French88274812006-03-09 22:21:45 +00003295 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296
3297 /* BB eventually could optimize out free and realloc of buf */
3298 /* for this case */
3299 if (rc == -EAGAIN)
3300 goto findFirstRetry;
3301 } else { /* decode response */
3302 /* BB remember to free buffer if error BB */
3303 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3304 if(rc == 0) {
3305 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3306 psrch_inf->unicode = TRUE;
3307 else
3308 psrch_inf->unicode = FALSE;
3309
3310 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003311 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 psrch_inf->srch_entries_start =
3313 (char *) &pSMBr->hdr.Protocol +
3314 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3316 le16_to_cpu(pSMBr->t2.ParameterOffset));
3317
3318 if(parms->EndofSearch)
3319 psrch_inf->endOfSearch = TRUE;
3320 else
3321 psrch_inf->endOfSearch = FALSE;
3322
3323 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003324 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 *pnetfid = parms->SearchHandle;
3327 } else {
3328 cifs_buf_release(pSMB);
3329 }
3330 }
3331
3332 return rc;
3333}
3334
3335int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3336 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3337{
3338 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3339 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3340 T2_FNEXT_RSP_PARMS * parms;
3341 char *response_data;
3342 int rc = 0;
3343 int bytes_returned, name_len;
3344 __u16 params, byte_count;
3345
3346 cFYI(1, ("In FindNext"));
3347
3348 if(psrch_inf->endOfSearch == TRUE)
3349 return -ENOENT;
3350
3351 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3352 (void **) &pSMBr);
3353 if (rc)
3354 return rc;
3355
3356 params = 14; /* includes 2 bytes of null string, converted to LE below */
3357 byte_count = 0;
3358 pSMB->TotalDataCount = 0; /* no EAs */
3359 pSMB->MaxParameterCount = cpu_to_le16(8);
3360 pSMB->MaxDataCount =
3361 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3362 pSMB->MaxSetupCount = 0;
3363 pSMB->Reserved = 0;
3364 pSMB->Flags = 0;
3365 pSMB->Timeout = 0;
3366 pSMB->Reserved2 = 0;
3367 pSMB->ParameterOffset = cpu_to_le16(
3368 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3369 pSMB->DataCount = 0;
3370 pSMB->DataOffset = 0;
3371 pSMB->SetupCount = 1;
3372 pSMB->Reserved3 = 0;
3373 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3374 pSMB->SearchHandle = searchHandle; /* always kept as le */
3375 pSMB->SearchCount =
3376 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3377 /* test for Unix extensions */
3378/* if (tcon->ses->capabilities & CAP_UNIX) {
3379 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3380 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3381 } else {
3382 pSMB->InformationLevel =
3383 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3384 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3385 } */
3386 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3387 pSMB->ResumeKey = psrch_inf->resume_key;
3388 pSMB->SearchFlags =
3389 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3390
3391 name_len = psrch_inf->resume_name_len;
3392 params += name_len;
3393 if(name_len < PATH_MAX) {
3394 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3395 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003396 /* 14 byte parm len above enough for 2 byte null terminator */
3397 pSMB->ResumeFileName[name_len] = 0;
3398 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 } else {
3400 rc = -EINVAL;
3401 goto FNext2_err_exit;
3402 }
3403 byte_count = params + 1 /* pad */ ;
3404 pSMB->TotalParameterCount = cpu_to_le16(params);
3405 pSMB->ParameterCount = pSMB->TotalParameterCount;
3406 pSMB->hdr.smb_buf_length += byte_count;
3407 pSMB->ByteCount = cpu_to_le16(byte_count);
3408
3409 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3410 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003411 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 if (rc) {
3413 if (rc == -EBADF) {
3414 psrch_inf->endOfSearch = TRUE;
3415 rc = 0; /* search probably was closed at end of search above */
3416 } else
3417 cFYI(1, ("FindNext returned = %d", rc));
3418 } else { /* decode response */
3419 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3420
3421 if(rc == 0) {
3422 /* BB fixme add lock for file (srch_info) struct here */
3423 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3424 psrch_inf->unicode = TRUE;
3425 else
3426 psrch_inf->unicode = FALSE;
3427 response_data = (char *) &pSMBr->hdr.Protocol +
3428 le16_to_cpu(pSMBr->t2.ParameterOffset);
3429 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3430 response_data = (char *)&pSMBr->hdr.Protocol +
3431 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003432 if(psrch_inf->smallBuf)
3433 cifs_small_buf_release(
3434 psrch_inf->ntwrk_buf_start);
3435 else
3436 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 psrch_inf->srch_entries_start = response_data;
3438 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003439 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 if(parms->EndofSearch)
3441 psrch_inf->endOfSearch = TRUE;
3442 else
3443 psrch_inf->endOfSearch = FALSE;
3444
3445 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3446 psrch_inf->index_of_last_entry +=
3447 psrch_inf->entries_in_buffer;
3448/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3449
3450 /* BB fixme add unlock here */
3451 }
3452
3453 }
3454
3455 /* BB On error, should we leave previous search buf (and count and
3456 last entry fields) intact or free the previous one? */
3457
3458 /* Note: On -EAGAIN error only caller can retry on handle based calls
3459 since file handle passed in no longer valid */
3460FNext2_err_exit:
3461 if (rc != 0)
3462 cifs_buf_release(pSMB);
3463
3464 return rc;
3465}
3466
3467int
3468CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3469{
3470 int rc = 0;
3471 FINDCLOSE_REQ *pSMB = NULL;
3472 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3473 int bytes_returned;
3474
3475 cFYI(1, ("In CIFSSMBFindClose"));
3476 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3477
3478 /* no sense returning error if session restarted
3479 as file handle has been closed */
3480 if(rc == -EAGAIN)
3481 return 0;
3482 if (rc)
3483 return rc;
3484
3485 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3486 pSMB->FileID = searchHandle;
3487 pSMB->ByteCount = 0;
3488 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3489 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3490 if (rc) {
3491 cERROR(1, ("Send error in FindClose = %d", rc));
3492 }
Steve Frencha4544342005-08-24 13:59:35 -07003493 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 cifs_small_buf_release(pSMB);
3495
3496 /* Since session is dead, search handle closed on server already */
3497 if (rc == -EAGAIN)
3498 rc = 0;
3499
3500 return rc;
3501}
3502
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503int
3504CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3505 const unsigned char *searchName,
3506 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003507 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508{
3509 int rc = 0;
3510 TRANSACTION2_QPI_REQ *pSMB = NULL;
3511 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3512 int name_len, bytes_returned;
3513 __u16 params, byte_count;
3514
3515 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3516 if(tcon == NULL)
3517 return -ENODEV;
3518
3519GetInodeNumberRetry:
3520 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3521 (void **) &pSMBr);
3522 if (rc)
3523 return rc;
3524
3525
3526 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3527 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003528 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003529 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 name_len++; /* trailing null */
3531 name_len *= 2;
3532 } else { /* BB improve the check for buffer overruns BB */
3533 name_len = strnlen(searchName, PATH_MAX);
3534 name_len++; /* trailing null */
3535 strncpy(pSMB->FileName, searchName, name_len);
3536 }
3537
3538 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3539 pSMB->TotalDataCount = 0;
3540 pSMB->MaxParameterCount = cpu_to_le16(2);
3541 /* BB find exact max data count below from sess structure BB */
3542 pSMB->MaxDataCount = cpu_to_le16(4000);
3543 pSMB->MaxSetupCount = 0;
3544 pSMB->Reserved = 0;
3545 pSMB->Flags = 0;
3546 pSMB->Timeout = 0;
3547 pSMB->Reserved2 = 0;
3548 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3549 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3550 pSMB->DataCount = 0;
3551 pSMB->DataOffset = 0;
3552 pSMB->SetupCount = 1;
3553 pSMB->Reserved3 = 0;
3554 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3555 byte_count = params + 1 /* pad */ ;
3556 pSMB->TotalParameterCount = cpu_to_le16(params);
3557 pSMB->ParameterCount = pSMB->TotalParameterCount;
3558 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3559 pSMB->Reserved4 = 0;
3560 pSMB->hdr.smb_buf_length += byte_count;
3561 pSMB->ByteCount = cpu_to_le16(byte_count);
3562
3563 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3564 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3565 if (rc) {
3566 cFYI(1, ("error %d in QueryInternalInfo", rc));
3567 } else {
3568 /* decode response */
3569 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3570 if (rc || (pSMBr->ByteCount < 2))
3571 /* BB also check enough total bytes returned */
3572 /* If rc should we check for EOPNOSUPP and
3573 disable the srvino flag? or in caller? */
3574 rc = -EIO; /* bad smb */
3575 else {
3576 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3577 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3578 struct file_internal_info * pfinfo;
3579 /* BB Do we need a cast or hash here ? */
3580 if(count < 8) {
3581 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3582 rc = -EIO;
3583 goto GetInodeNumOut;
3584 }
3585 pfinfo = (struct file_internal_info *)
3586 (data_offset + (char *) &pSMBr->hdr.Protocol);
3587 *inode_number = pfinfo->UniqueId;
3588 }
3589 }
3590GetInodeNumOut:
3591 cifs_buf_release(pSMB);
3592 if (rc == -EAGAIN)
3593 goto GetInodeNumberRetry;
3594 return rc;
3595}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597int
3598CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3599 const unsigned char *searchName,
3600 unsigned char **targetUNCs,
3601 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003602 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603{
3604/* TRANS2_GET_DFS_REFERRAL */
3605 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3606 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3607 struct dfs_referral_level_3 * referrals = NULL;
3608 int rc = 0;
3609 int bytes_returned;
3610 int name_len;
3611 unsigned int i;
3612 char * temp;
3613 __u16 params, byte_count;
3614 *number_of_UNC_in_array = 0;
3615 *targetUNCs = NULL;
3616
3617 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3618 if (ses == NULL)
3619 return -ENODEV;
3620getDFSRetry:
3621 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3622 (void **) &pSMBr);
3623 if (rc)
3624 return rc;
Steve French1982c342005-08-17 12:38:22 -07003625
3626 /* server pointer checked in called function,
3627 but should never be null here anyway */
3628 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 pSMB->hdr.Tid = ses->ipc_tid;
3630 pSMB->hdr.Uid = ses->Suid;
3631 if (ses->capabilities & CAP_STATUS32) {
3632 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3633 }
3634 if (ses->capabilities & CAP_DFS) {
3635 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3636 }
3637
3638 if (ses->capabilities & CAP_UNICODE) {
3639 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3640 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003641 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003642 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 name_len++; /* trailing null */
3644 name_len *= 2;
3645 } else { /* BB improve the check for buffer overruns BB */
3646 name_len = strnlen(searchName, PATH_MAX);
3647 name_len++; /* trailing null */
3648 strncpy(pSMB->RequestFileName, searchName, name_len);
3649 }
3650
3651 params = 2 /* level */ + name_len /*includes null */ ;
3652 pSMB->TotalDataCount = 0;
3653 pSMB->DataCount = 0;
3654 pSMB->DataOffset = 0;
3655 pSMB->MaxParameterCount = 0;
3656 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3657 pSMB->MaxSetupCount = 0;
3658 pSMB->Reserved = 0;
3659 pSMB->Flags = 0;
3660 pSMB->Timeout = 0;
3661 pSMB->Reserved2 = 0;
3662 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3663 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3664 pSMB->SetupCount = 1;
3665 pSMB->Reserved3 = 0;
3666 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3667 byte_count = params + 3 /* pad */ ;
3668 pSMB->ParameterCount = cpu_to_le16(params);
3669 pSMB->TotalParameterCount = pSMB->ParameterCount;
3670 pSMB->MaxReferralLevel = cpu_to_le16(3);
3671 pSMB->hdr.smb_buf_length += byte_count;
3672 pSMB->ByteCount = cpu_to_le16(byte_count);
3673
3674 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3675 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3676 if (rc) {
3677 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3678 } else { /* decode response */
3679/* BB Add logic to parse referrals here */
3680 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3681
3682 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3683 rc = -EIO; /* bad smb */
3684 else {
3685 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3686 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3687
3688 cFYI(1,
3689 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3690 pSMBr->ByteCount, data_offset));
3691 referrals =
3692 (struct dfs_referral_level_3 *)
3693 (8 /* sizeof start of data block */ +
3694 data_offset +
3695 (char *) &pSMBr->hdr.Protocol);
3696 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",
3697 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)));
3698 /* BB This field is actually two bytes in from start of
3699 data block so we could do safety check that DataBlock
3700 begins at address of pSMBr->NumberOfReferrals */
3701 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3702
3703 /* BB Fix below so can return more than one referral */
3704 if(*number_of_UNC_in_array > 1)
3705 *number_of_UNC_in_array = 1;
3706
3707 /* get the length of the strings describing refs */
3708 name_len = 0;
3709 for(i=0;i<*number_of_UNC_in_array;i++) {
3710 /* make sure that DfsPathOffset not past end */
3711 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3712 if (offset > data_count) {
3713 /* if invalid referral, stop here and do
3714 not try to copy any more */
3715 *number_of_UNC_in_array = i;
3716 break;
3717 }
3718 temp = ((char *)referrals) + offset;
3719
3720 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3721 name_len += UniStrnlen((wchar_t *)temp,data_count);
3722 } else {
3723 name_len += strnlen(temp,data_count);
3724 }
3725 referrals++;
3726 /* BB add check that referral pointer does not fall off end PDU */
3727
3728 }
3729 /* BB add check for name_len bigger than bcc */
3730 *targetUNCs =
3731 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3732 if(*targetUNCs == NULL) {
3733 rc = -ENOMEM;
3734 goto GetDFSRefExit;
3735 }
3736 /* copy the ref strings */
3737 referrals =
3738 (struct dfs_referral_level_3 *)
3739 (8 /* sizeof data hdr */ +
3740 data_offset +
3741 (char *) &pSMBr->hdr.Protocol);
3742
3743 for(i=0;i<*number_of_UNC_in_array;i++) {
3744 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3745 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3746 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003747 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 } else {
3749 strncpy(*targetUNCs,temp,name_len);
3750 }
3751 /* BB update target_uncs pointers */
3752 referrals++;
3753 }
3754 temp = *targetUNCs;
3755 temp[name_len] = 0;
3756 }
3757
3758 }
3759GetDFSRefExit:
3760 if (pSMB)
3761 cifs_buf_release(pSMB);
3762
3763 if (rc == -EAGAIN)
3764 goto getDFSRetry;
3765
3766 return rc;
3767}
3768
Steve French20962432005-09-21 22:05:57 -07003769/* Query File System Info such as free space to old servers such as Win 9x */
3770int
3771SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3772{
3773/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3774 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3775 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3776 FILE_SYSTEM_ALLOC_INFO *response_data;
3777 int rc = 0;
3778 int bytes_returned = 0;
3779 __u16 params, byte_count;
3780
3781 cFYI(1, ("OldQFSInfo"));
3782oldQFSInfoRetry:
3783 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3784 (void **) &pSMBr);
3785 if (rc)
3786 return rc;
3787 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3788 (void **) &pSMBr);
3789 if (rc)
3790 return rc;
3791
3792 params = 2; /* level */
3793 pSMB->TotalDataCount = 0;
3794 pSMB->MaxParameterCount = cpu_to_le16(2);
3795 pSMB->MaxDataCount = cpu_to_le16(1000);
3796 pSMB->MaxSetupCount = 0;
3797 pSMB->Reserved = 0;
3798 pSMB->Flags = 0;
3799 pSMB->Timeout = 0;
3800 pSMB->Reserved2 = 0;
3801 byte_count = params + 1 /* pad */ ;
3802 pSMB->TotalParameterCount = cpu_to_le16(params);
3803 pSMB->ParameterCount = pSMB->TotalParameterCount;
3804 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3805 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3806 pSMB->DataCount = 0;
3807 pSMB->DataOffset = 0;
3808 pSMB->SetupCount = 1;
3809 pSMB->Reserved3 = 0;
3810 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3811 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3812 pSMB->hdr.smb_buf_length += byte_count;
3813 pSMB->ByteCount = cpu_to_le16(byte_count);
3814
3815 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3816 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3817 if (rc) {
3818 cFYI(1, ("Send error in QFSInfo = %d", rc));
3819 } else { /* decode response */
3820 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3821
3822 if (rc || (pSMBr->ByteCount < 18))
3823 rc = -EIO; /* bad smb */
3824 else {
3825 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3826 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3827 pSMBr->ByteCount, data_offset));
3828
3829 response_data =
3830 (FILE_SYSTEM_ALLOC_INFO *)
3831 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3832 FSData->f_bsize =
3833 le16_to_cpu(response_data->BytesPerSector) *
3834 le32_to_cpu(response_data->
3835 SectorsPerAllocationUnit);
3836 FSData->f_blocks =
3837 le32_to_cpu(response_data->TotalAllocationUnits);
3838 FSData->f_bfree = FSData->f_bavail =
3839 le32_to_cpu(response_data->FreeAllocationUnits);
3840 cFYI(1,
3841 ("Blocks: %lld Free: %lld Block size %ld",
3842 (unsigned long long)FSData->f_blocks,
3843 (unsigned long long)FSData->f_bfree,
3844 FSData->f_bsize));
3845 }
3846 }
3847 cifs_buf_release(pSMB);
3848
3849 if (rc == -EAGAIN)
3850 goto oldQFSInfoRetry;
3851
3852 return rc;
3853}
3854
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855int
Steve French737b7582005-04-28 22:41:06 -07003856CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857{
3858/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3859 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3860 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3861 FILE_SYSTEM_INFO *response_data;
3862 int rc = 0;
3863 int bytes_returned = 0;
3864 __u16 params, byte_count;
3865
3866 cFYI(1, ("In QFSInfo"));
3867QFSInfoRetry:
3868 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3869 (void **) &pSMBr);
3870 if (rc)
3871 return rc;
3872
3873 params = 2; /* level */
3874 pSMB->TotalDataCount = 0;
3875 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003876 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 pSMB->MaxSetupCount = 0;
3878 pSMB->Reserved = 0;
3879 pSMB->Flags = 0;
3880 pSMB->Timeout = 0;
3881 pSMB->Reserved2 = 0;
3882 byte_count = params + 1 /* pad */ ;
3883 pSMB->TotalParameterCount = cpu_to_le16(params);
3884 pSMB->ParameterCount = pSMB->TotalParameterCount;
3885 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3886 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3887 pSMB->DataCount = 0;
3888 pSMB->DataOffset = 0;
3889 pSMB->SetupCount = 1;
3890 pSMB->Reserved3 = 0;
3891 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3892 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3893 pSMB->hdr.smb_buf_length += byte_count;
3894 pSMB->ByteCount = cpu_to_le16(byte_count);
3895
3896 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3897 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3898 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003899 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 } else { /* decode response */
3901 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3902
Steve French20962432005-09-21 22:05:57 -07003903 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 rc = -EIO; /* bad smb */
3905 else {
3906 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
3908 response_data =
3909 (FILE_SYSTEM_INFO
3910 *) (((char *) &pSMBr->hdr.Protocol) +
3911 data_offset);
3912 FSData->f_bsize =
3913 le32_to_cpu(response_data->BytesPerSector) *
3914 le32_to_cpu(response_data->
3915 SectorsPerAllocationUnit);
3916 FSData->f_blocks =
3917 le64_to_cpu(response_data->TotalAllocationUnits);
3918 FSData->f_bfree = FSData->f_bavail =
3919 le64_to_cpu(response_data->FreeAllocationUnits);
3920 cFYI(1,
3921 ("Blocks: %lld Free: %lld Block size %ld",
3922 (unsigned long long)FSData->f_blocks,
3923 (unsigned long long)FSData->f_bfree,
3924 FSData->f_bsize));
3925 }
3926 }
3927 cifs_buf_release(pSMB);
3928
3929 if (rc == -EAGAIN)
3930 goto QFSInfoRetry;
3931
3932 return rc;
3933}
3934
3935int
Steve French737b7582005-04-28 22:41:06 -07003936CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937{
3938/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3939 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3940 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3941 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3942 int rc = 0;
3943 int bytes_returned = 0;
3944 __u16 params, byte_count;
3945
3946 cFYI(1, ("In QFSAttributeInfo"));
3947QFSAttributeRetry:
3948 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3949 (void **) &pSMBr);
3950 if (rc)
3951 return rc;
3952
3953 params = 2; /* level */
3954 pSMB->TotalDataCount = 0;
3955 pSMB->MaxParameterCount = cpu_to_le16(2);
3956 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3957 pSMB->MaxSetupCount = 0;
3958 pSMB->Reserved = 0;
3959 pSMB->Flags = 0;
3960 pSMB->Timeout = 0;
3961 pSMB->Reserved2 = 0;
3962 byte_count = params + 1 /* pad */ ;
3963 pSMB->TotalParameterCount = cpu_to_le16(params);
3964 pSMB->ParameterCount = pSMB->TotalParameterCount;
3965 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3966 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3967 pSMB->DataCount = 0;
3968 pSMB->DataOffset = 0;
3969 pSMB->SetupCount = 1;
3970 pSMB->Reserved3 = 0;
3971 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3972 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3973 pSMB->hdr.smb_buf_length += byte_count;
3974 pSMB->ByteCount = cpu_to_le16(byte_count);
3975
3976 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3977 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3978 if (rc) {
3979 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3980 } else { /* decode response */
3981 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3982
3983 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3984 rc = -EIO; /* bad smb */
3985 } else {
3986 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3987 response_data =
3988 (FILE_SYSTEM_ATTRIBUTE_INFO
3989 *) (((char *) &pSMBr->hdr.Protocol) +
3990 data_offset);
3991 memcpy(&tcon->fsAttrInfo, response_data,
3992 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3993 }
3994 }
3995 cifs_buf_release(pSMB);
3996
3997 if (rc == -EAGAIN)
3998 goto QFSAttributeRetry;
3999
4000 return rc;
4001}
4002
4003int
Steve French737b7582005-04-28 22:41:06 -07004004CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005{
4006/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4007 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4008 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4009 FILE_SYSTEM_DEVICE_INFO *response_data;
4010 int rc = 0;
4011 int bytes_returned = 0;
4012 __u16 params, byte_count;
4013
4014 cFYI(1, ("In QFSDeviceInfo"));
4015QFSDeviceRetry:
4016 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4017 (void **) &pSMBr);
4018 if (rc)
4019 return rc;
4020
4021 params = 2; /* level */
4022 pSMB->TotalDataCount = 0;
4023 pSMB->MaxParameterCount = cpu_to_le16(2);
4024 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4025 pSMB->MaxSetupCount = 0;
4026 pSMB->Reserved = 0;
4027 pSMB->Flags = 0;
4028 pSMB->Timeout = 0;
4029 pSMB->Reserved2 = 0;
4030 byte_count = params + 1 /* pad */ ;
4031 pSMB->TotalParameterCount = cpu_to_le16(params);
4032 pSMB->ParameterCount = pSMB->TotalParameterCount;
4033 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4034 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4035
4036 pSMB->DataCount = 0;
4037 pSMB->DataOffset = 0;
4038 pSMB->SetupCount = 1;
4039 pSMB->Reserved3 = 0;
4040 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4041 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4042 pSMB->hdr.smb_buf_length += byte_count;
4043 pSMB->ByteCount = cpu_to_le16(byte_count);
4044
4045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4047 if (rc) {
4048 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4049 } else { /* decode response */
4050 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4051
4052 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4053 rc = -EIO; /* bad smb */
4054 else {
4055 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4056 response_data =
Steve French737b7582005-04-28 22:41:06 -07004057 (FILE_SYSTEM_DEVICE_INFO *)
4058 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 data_offset);
4060 memcpy(&tcon->fsDevInfo, response_data,
4061 sizeof (FILE_SYSTEM_DEVICE_INFO));
4062 }
4063 }
4064 cifs_buf_release(pSMB);
4065
4066 if (rc == -EAGAIN)
4067 goto QFSDeviceRetry;
4068
4069 return rc;
4070}
4071
4072int
Steve French737b7582005-04-28 22:41:06 -07004073CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074{
4075/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4076 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4077 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4078 FILE_SYSTEM_UNIX_INFO *response_data;
4079 int rc = 0;
4080 int bytes_returned = 0;
4081 __u16 params, byte_count;
4082
4083 cFYI(1, ("In QFSUnixInfo"));
4084QFSUnixRetry:
4085 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4086 (void **) &pSMBr);
4087 if (rc)
4088 return rc;
4089
4090 params = 2; /* level */
4091 pSMB->TotalDataCount = 0;
4092 pSMB->DataCount = 0;
4093 pSMB->DataOffset = 0;
4094 pSMB->MaxParameterCount = cpu_to_le16(2);
4095 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4096 pSMB->MaxSetupCount = 0;
4097 pSMB->Reserved = 0;
4098 pSMB->Flags = 0;
4099 pSMB->Timeout = 0;
4100 pSMB->Reserved2 = 0;
4101 byte_count = params + 1 /* pad */ ;
4102 pSMB->ParameterCount = cpu_to_le16(params);
4103 pSMB->TotalParameterCount = pSMB->ParameterCount;
4104 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4105 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4106 pSMB->SetupCount = 1;
4107 pSMB->Reserved3 = 0;
4108 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4109 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4110 pSMB->hdr.smb_buf_length += byte_count;
4111 pSMB->ByteCount = cpu_to_le16(byte_count);
4112
4113 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4114 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4115 if (rc) {
4116 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4117 } else { /* decode response */
4118 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4119
4120 if (rc || (pSMBr->ByteCount < 13)) {
4121 rc = -EIO; /* bad smb */
4122 } else {
4123 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4124 response_data =
4125 (FILE_SYSTEM_UNIX_INFO
4126 *) (((char *) &pSMBr->hdr.Protocol) +
4127 data_offset);
4128 memcpy(&tcon->fsUnixInfo, response_data,
4129 sizeof (FILE_SYSTEM_UNIX_INFO));
4130 }
4131 }
4132 cifs_buf_release(pSMB);
4133
4134 if (rc == -EAGAIN)
4135 goto QFSUnixRetry;
4136
4137
4138 return rc;
4139}
4140
Jeremy Allisonac670552005-06-22 17:26:35 -07004141int
Steve French45abc6e2005-06-23 13:42:03 -05004142CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004143{
4144/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4145 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4146 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4147 int rc = 0;
4148 int bytes_returned = 0;
4149 __u16 params, param_offset, offset, byte_count;
4150
4151 cFYI(1, ("In SETFSUnixInfo"));
4152SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004153 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004154 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4155 (void **) &pSMBr);
4156 if (rc)
4157 return rc;
4158
4159 params = 4; /* 2 bytes zero followed by info level. */
4160 pSMB->MaxSetupCount = 0;
4161 pSMB->Reserved = 0;
4162 pSMB->Flags = 0;
4163 pSMB->Timeout = 0;
4164 pSMB->Reserved2 = 0;
4165 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4166 offset = param_offset + params;
4167
4168 pSMB->MaxParameterCount = cpu_to_le16(4);
4169 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4170 pSMB->SetupCount = 1;
4171 pSMB->Reserved3 = 0;
4172 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4173 byte_count = 1 /* pad */ + params + 12;
4174
4175 pSMB->DataCount = cpu_to_le16(12);
4176 pSMB->ParameterCount = cpu_to_le16(params);
4177 pSMB->TotalDataCount = pSMB->DataCount;
4178 pSMB->TotalParameterCount = pSMB->ParameterCount;
4179 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4180 pSMB->DataOffset = cpu_to_le16(offset);
4181
4182 /* Params. */
4183 pSMB->FileNum = 0;
4184 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4185
4186 /* Data. */
4187 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4188 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4189 pSMB->ClientUnixCap = cpu_to_le64(cap);
4190
4191 pSMB->hdr.smb_buf_length += byte_count;
4192 pSMB->ByteCount = cpu_to_le16(byte_count);
4193
4194 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4195 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4196 if (rc) {
4197 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4198 } else { /* decode response */
4199 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4200 if (rc) {
4201 rc = -EIO; /* bad smb */
4202 }
4203 }
4204 cifs_buf_release(pSMB);
4205
4206 if (rc == -EAGAIN)
4207 goto SETFSUnixRetry;
4208
4209 return rc;
4210}
4211
4212
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213
4214int
4215CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004216 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217{
4218/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4219 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4220 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4221 FILE_SYSTEM_POSIX_INFO *response_data;
4222 int rc = 0;
4223 int bytes_returned = 0;
4224 __u16 params, byte_count;
4225
4226 cFYI(1, ("In QFSPosixInfo"));
4227QFSPosixRetry:
4228 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4229 (void **) &pSMBr);
4230 if (rc)
4231 return rc;
4232
4233 params = 2; /* level */
4234 pSMB->TotalDataCount = 0;
4235 pSMB->DataCount = 0;
4236 pSMB->DataOffset = 0;
4237 pSMB->MaxParameterCount = cpu_to_le16(2);
4238 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4239 pSMB->MaxSetupCount = 0;
4240 pSMB->Reserved = 0;
4241 pSMB->Flags = 0;
4242 pSMB->Timeout = 0;
4243 pSMB->Reserved2 = 0;
4244 byte_count = params + 1 /* pad */ ;
4245 pSMB->ParameterCount = cpu_to_le16(params);
4246 pSMB->TotalParameterCount = pSMB->ParameterCount;
4247 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4248 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4249 pSMB->SetupCount = 1;
4250 pSMB->Reserved3 = 0;
4251 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4252 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4253 pSMB->hdr.smb_buf_length += byte_count;
4254 pSMB->ByteCount = cpu_to_le16(byte_count);
4255
4256 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4257 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4258 if (rc) {
4259 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4260 } else { /* decode response */
4261 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4262
4263 if (rc || (pSMBr->ByteCount < 13)) {
4264 rc = -EIO; /* bad smb */
4265 } else {
4266 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4267 response_data =
4268 (FILE_SYSTEM_POSIX_INFO
4269 *) (((char *) &pSMBr->hdr.Protocol) +
4270 data_offset);
4271 FSData->f_bsize =
4272 le32_to_cpu(response_data->BlockSize);
4273 FSData->f_blocks =
4274 le64_to_cpu(response_data->TotalBlocks);
4275 FSData->f_bfree =
4276 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004277 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 FSData->f_bavail = FSData->f_bfree;
4279 } else {
4280 FSData->f_bavail =
4281 le64_to_cpu(response_data->UserBlocksAvail);
4282 }
Steve French70ca7342005-09-22 16:32:06 -07004283 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 FSData->f_files =
4285 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004286 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 FSData->f_ffree =
4288 le64_to_cpu(response_data->FreeFileNodes);
4289 }
4290 }
4291 cifs_buf_release(pSMB);
4292
4293 if (rc == -EAGAIN)
4294 goto QFSPosixRetry;
4295
4296 return rc;
4297}
4298
4299
4300/* We can not use write of zero bytes trick to
4301 set file size due to need for large file support. Also note that
4302 this SetPathInfo is preferred to SetFileInfo based method in next
4303 routine which is only needed to work around a sharing violation bug
4304 in Samba which this routine can run into */
4305
4306int
4307CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004308 __u64 size, int SetAllocation,
4309 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310{
4311 struct smb_com_transaction2_spi_req *pSMB = NULL;
4312 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4313 struct file_end_of_file_info *parm_data;
4314 int name_len;
4315 int rc = 0;
4316 int bytes_returned = 0;
4317 __u16 params, byte_count, data_count, param_offset, offset;
4318
4319 cFYI(1, ("In SetEOF"));
4320SetEOFRetry:
4321 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4322 (void **) &pSMBr);
4323 if (rc)
4324 return rc;
4325
4326 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4327 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004328 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004329 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 name_len++; /* trailing null */
4331 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004332 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 name_len = strnlen(fileName, PATH_MAX);
4334 name_len++; /* trailing null */
4335 strncpy(pSMB->FileName, fileName, name_len);
4336 }
4337 params = 6 + name_len;
4338 data_count = sizeof (struct file_end_of_file_info);
4339 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004340 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 pSMB->MaxSetupCount = 0;
4342 pSMB->Reserved = 0;
4343 pSMB->Flags = 0;
4344 pSMB->Timeout = 0;
4345 pSMB->Reserved2 = 0;
4346 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4347 InformationLevel) - 4;
4348 offset = param_offset + params;
4349 if(SetAllocation) {
4350 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4351 pSMB->InformationLevel =
4352 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4353 else
4354 pSMB->InformationLevel =
4355 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4356 } else /* Set File Size */ {
4357 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4358 pSMB->InformationLevel =
4359 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4360 else
4361 pSMB->InformationLevel =
4362 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4363 }
4364
4365 parm_data =
4366 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4367 offset);
4368 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4369 pSMB->DataOffset = cpu_to_le16(offset);
4370 pSMB->SetupCount = 1;
4371 pSMB->Reserved3 = 0;
4372 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4373 byte_count = 3 /* pad */ + params + data_count;
4374 pSMB->DataCount = cpu_to_le16(data_count);
4375 pSMB->TotalDataCount = pSMB->DataCount;
4376 pSMB->ParameterCount = cpu_to_le16(params);
4377 pSMB->TotalParameterCount = pSMB->ParameterCount;
4378 pSMB->Reserved4 = 0;
4379 pSMB->hdr.smb_buf_length += byte_count;
4380 parm_data->FileSize = cpu_to_le64(size);
4381 pSMB->ByteCount = cpu_to_le16(byte_count);
4382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4383 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4384 if (rc) {
4385 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4386 }
4387
4388 cifs_buf_release(pSMB);
4389
4390 if (rc == -EAGAIN)
4391 goto SetEOFRetry;
4392
4393 return rc;
4394}
4395
4396int
4397CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4398 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4399{
4400 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4401 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4402 char *data_offset;
4403 struct file_end_of_file_info *parm_data;
4404 int rc = 0;
4405 int bytes_returned = 0;
4406 __u16 params, param_offset, offset, byte_count, count;
4407
4408 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4409 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004410 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4411
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 if (rc)
4413 return rc;
4414
Steve Frenchcd634992005-04-28 22:41:10 -07004415 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4416
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4418 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4419
4420 params = 6;
4421 pSMB->MaxSetupCount = 0;
4422 pSMB->Reserved = 0;
4423 pSMB->Flags = 0;
4424 pSMB->Timeout = 0;
4425 pSMB->Reserved2 = 0;
4426 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4427 offset = param_offset + params;
4428
4429 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4430
4431 count = sizeof(struct file_end_of_file_info);
4432 pSMB->MaxParameterCount = cpu_to_le16(2);
4433 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4434 pSMB->SetupCount = 1;
4435 pSMB->Reserved3 = 0;
4436 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4437 byte_count = 3 /* pad */ + params + count;
4438 pSMB->DataCount = cpu_to_le16(count);
4439 pSMB->ParameterCount = cpu_to_le16(params);
4440 pSMB->TotalDataCount = pSMB->DataCount;
4441 pSMB->TotalParameterCount = pSMB->ParameterCount;
4442 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4443 parm_data =
4444 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4445 offset);
4446 pSMB->DataOffset = cpu_to_le16(offset);
4447 parm_data->FileSize = cpu_to_le64(size);
4448 pSMB->Fid = fid;
4449 if(SetAllocation) {
4450 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4451 pSMB->InformationLevel =
4452 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4453 else
4454 pSMB->InformationLevel =
4455 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4456 } else /* Set File Size */ {
4457 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4458 pSMB->InformationLevel =
4459 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4460 else
4461 pSMB->InformationLevel =
4462 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4463 }
4464 pSMB->Reserved4 = 0;
4465 pSMB->hdr.smb_buf_length += byte_count;
4466 pSMB->ByteCount = cpu_to_le16(byte_count);
4467 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4468 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4469 if (rc) {
4470 cFYI(1,
4471 ("Send error in SetFileInfo (SetFileSize) = %d",
4472 rc));
4473 }
4474
4475 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004476 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477
4478 /* Note: On -EAGAIN error only caller can retry on handle based calls
4479 since file handle passed in no longer valid */
4480
4481 return rc;
4482}
4483
4484/* Some legacy servers such as NT4 require that the file times be set on
4485 an open handle, rather than by pathname - this is awkward due to
4486 potential access conflicts on the open, but it is unavoidable for these
4487 old servers since the only other choice is to go from 100 nanosecond DCE
4488 time and resort to the original setpathinfo level which takes the ancient
4489 DOS time format with 2 second granularity */
4490int
4491CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4492 __u16 fid)
4493{
4494 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4495 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4496 char *data_offset;
4497 int rc = 0;
4498 int bytes_returned = 0;
4499 __u16 params, param_offset, offset, byte_count, count;
4500
4501 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004502 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4503
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 if (rc)
4505 return rc;
4506
Steve Frenchcd634992005-04-28 22:41:10 -07004507 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4508
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 /* At this point there is no need to override the current pid
4510 with the pid of the opener, but that could change if we someday
4511 use an existing handle (rather than opening one on the fly) */
4512 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4513 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4514
4515 params = 6;
4516 pSMB->MaxSetupCount = 0;
4517 pSMB->Reserved = 0;
4518 pSMB->Flags = 0;
4519 pSMB->Timeout = 0;
4520 pSMB->Reserved2 = 0;
4521 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4522 offset = param_offset + params;
4523
4524 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4525
4526 count = sizeof (FILE_BASIC_INFO);
4527 pSMB->MaxParameterCount = cpu_to_le16(2);
4528 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4529 pSMB->SetupCount = 1;
4530 pSMB->Reserved3 = 0;
4531 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4532 byte_count = 3 /* pad */ + params + count;
4533 pSMB->DataCount = cpu_to_le16(count);
4534 pSMB->ParameterCount = cpu_to_le16(params);
4535 pSMB->TotalDataCount = pSMB->DataCount;
4536 pSMB->TotalParameterCount = pSMB->ParameterCount;
4537 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4538 pSMB->DataOffset = cpu_to_le16(offset);
4539 pSMB->Fid = fid;
4540 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4541 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4542 else
4543 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4544 pSMB->Reserved4 = 0;
4545 pSMB->hdr.smb_buf_length += byte_count;
4546 pSMB->ByteCount = cpu_to_le16(byte_count);
4547 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4548 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4549 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4550 if (rc) {
4551 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4552 }
4553
Steve Frenchcd634992005-04-28 22:41:10 -07004554 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555
4556 /* Note: On -EAGAIN error only caller can retry on handle based calls
4557 since file handle passed in no longer valid */
4558
4559 return rc;
4560}
4561
4562
4563int
4564CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4565 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004566 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567{
4568 TRANSACTION2_SPI_REQ *pSMB = NULL;
4569 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4570 int name_len;
4571 int rc = 0;
4572 int bytes_returned = 0;
4573 char *data_offset;
4574 __u16 params, param_offset, offset, byte_count, count;
4575
4576 cFYI(1, ("In SetTimes"));
4577
4578SetTimesRetry:
4579 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4580 (void **) &pSMBr);
4581 if (rc)
4582 return rc;
4583
4584 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4585 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004586 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004587 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 name_len++; /* trailing null */
4589 name_len *= 2;
4590 } else { /* BB improve the check for buffer overruns BB */
4591 name_len = strnlen(fileName, PATH_MAX);
4592 name_len++; /* trailing null */
4593 strncpy(pSMB->FileName, fileName, name_len);
4594 }
4595
4596 params = 6 + name_len;
4597 count = sizeof (FILE_BASIC_INFO);
4598 pSMB->MaxParameterCount = cpu_to_le16(2);
4599 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4600 pSMB->MaxSetupCount = 0;
4601 pSMB->Reserved = 0;
4602 pSMB->Flags = 0;
4603 pSMB->Timeout = 0;
4604 pSMB->Reserved2 = 0;
4605 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4606 InformationLevel) - 4;
4607 offset = param_offset + params;
4608 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4609 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4610 pSMB->DataOffset = cpu_to_le16(offset);
4611 pSMB->SetupCount = 1;
4612 pSMB->Reserved3 = 0;
4613 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4614 byte_count = 3 /* pad */ + params + count;
4615
4616 pSMB->DataCount = cpu_to_le16(count);
4617 pSMB->ParameterCount = cpu_to_le16(params);
4618 pSMB->TotalDataCount = pSMB->DataCount;
4619 pSMB->TotalParameterCount = pSMB->ParameterCount;
4620 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4621 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4622 else
4623 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4624 pSMB->Reserved4 = 0;
4625 pSMB->hdr.smb_buf_length += byte_count;
4626 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4627 pSMB->ByteCount = cpu_to_le16(byte_count);
4628 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4629 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4630 if (rc) {
4631 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4632 }
4633
4634 cifs_buf_release(pSMB);
4635
4636 if (rc == -EAGAIN)
4637 goto SetTimesRetry;
4638
4639 return rc;
4640}
4641
4642/* Can not be used to set time stamps yet (due to old DOS time format) */
4643/* Can be used to set attributes */
4644#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4645 handling it anyway and NT4 was what we thought it would be needed for
4646 Do not delete it until we prove whether needed for Win9x though */
4647int
4648CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4649 __u16 dos_attrs, const struct nls_table *nls_codepage)
4650{
4651 SETATTR_REQ *pSMB = NULL;
4652 SETATTR_RSP *pSMBr = NULL;
4653 int rc = 0;
4654 int bytes_returned;
4655 int name_len;
4656
4657 cFYI(1, ("In SetAttrLegacy"));
4658
4659SetAttrLgcyRetry:
4660 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4661 (void **) &pSMBr);
4662 if (rc)
4663 return rc;
4664
4665 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4666 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004667 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 PATH_MAX, nls_codepage);
4669 name_len++; /* trailing null */
4670 name_len *= 2;
4671 } else { /* BB improve the check for buffer overruns BB */
4672 name_len = strnlen(fileName, PATH_MAX);
4673 name_len++; /* trailing null */
4674 strncpy(pSMB->fileName, fileName, name_len);
4675 }
4676 pSMB->attr = cpu_to_le16(dos_attrs);
4677 pSMB->BufferFormat = 0x04;
4678 pSMB->hdr.smb_buf_length += name_len + 1;
4679 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4680 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4681 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4682 if (rc) {
4683 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4684 }
4685
4686 cifs_buf_release(pSMB);
4687
4688 if (rc == -EAGAIN)
4689 goto SetAttrLgcyRetry;
4690
4691 return rc;
4692}
4693#endif /* temporarily unneeded SetAttr legacy function */
4694
4695int
4696CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004697 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4698 dev_t device, const struct nls_table *nls_codepage,
4699 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700{
4701 TRANSACTION2_SPI_REQ *pSMB = NULL;
4702 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4703 int name_len;
4704 int rc = 0;
4705 int bytes_returned = 0;
4706 FILE_UNIX_BASIC_INFO *data_offset;
4707 __u16 params, param_offset, offset, count, byte_count;
4708
4709 cFYI(1, ("In SetUID/GID/Mode"));
4710setPermsRetry:
4711 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4712 (void **) &pSMBr);
4713 if (rc)
4714 return rc;
4715
4716 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4717 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004718 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004719 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 name_len++; /* trailing null */
4721 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004722 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 name_len = strnlen(fileName, PATH_MAX);
4724 name_len++; /* trailing null */
4725 strncpy(pSMB->FileName, fileName, name_len);
4726 }
4727
4728 params = 6 + name_len;
4729 count = sizeof (FILE_UNIX_BASIC_INFO);
4730 pSMB->MaxParameterCount = cpu_to_le16(2);
4731 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4732 pSMB->MaxSetupCount = 0;
4733 pSMB->Reserved = 0;
4734 pSMB->Flags = 0;
4735 pSMB->Timeout = 0;
4736 pSMB->Reserved2 = 0;
4737 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4738 InformationLevel) - 4;
4739 offset = param_offset + params;
4740 data_offset =
4741 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4742 offset);
4743 memset(data_offset, 0, count);
4744 pSMB->DataOffset = cpu_to_le16(offset);
4745 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4746 pSMB->SetupCount = 1;
4747 pSMB->Reserved3 = 0;
4748 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4749 byte_count = 3 /* pad */ + params + count;
4750 pSMB->ParameterCount = cpu_to_le16(params);
4751 pSMB->DataCount = cpu_to_le16(count);
4752 pSMB->TotalParameterCount = pSMB->ParameterCount;
4753 pSMB->TotalDataCount = pSMB->DataCount;
4754 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4755 pSMB->Reserved4 = 0;
4756 pSMB->hdr.smb_buf_length += byte_count;
4757 data_offset->Uid = cpu_to_le64(uid);
4758 data_offset->Gid = cpu_to_le64(gid);
4759 /* better to leave device as zero when it is */
4760 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4761 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4762 data_offset->Permissions = cpu_to_le64(mode);
4763
4764 if(S_ISREG(mode))
4765 data_offset->Type = cpu_to_le32(UNIX_FILE);
4766 else if(S_ISDIR(mode))
4767 data_offset->Type = cpu_to_le32(UNIX_DIR);
4768 else if(S_ISLNK(mode))
4769 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4770 else if(S_ISCHR(mode))
4771 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4772 else if(S_ISBLK(mode))
4773 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4774 else if(S_ISFIFO(mode))
4775 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4776 else if(S_ISSOCK(mode))
4777 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4778
4779
4780 pSMB->ByteCount = cpu_to_le16(byte_count);
4781 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4782 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4783 if (rc) {
4784 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4785 }
4786
4787 if (pSMB)
4788 cifs_buf_release(pSMB);
4789 if (rc == -EAGAIN)
4790 goto setPermsRetry;
4791 return rc;
4792}
4793
4794int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004795 const int notify_subdirs, const __u16 netfid,
4796 __u32 filter, struct file * pfile, int multishot,
4797 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798{
4799 int rc = 0;
4800 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004801 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004802 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 int bytes_returned;
4804
4805 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4806 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4807 (void **) &pSMBr);
4808 if (rc)
4809 return rc;
4810
4811 pSMB->TotalParameterCount = 0 ;
4812 pSMB->TotalDataCount = 0;
4813 pSMB->MaxParameterCount = cpu_to_le32(2);
4814 /* BB find exact data count max from sess structure BB */
4815 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004816/* BB VERIFY verify which is correct for above BB */
4817 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4818 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4819
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 pSMB->MaxSetupCount = 4;
4821 pSMB->Reserved = 0;
4822 pSMB->ParameterOffset = 0;
4823 pSMB->DataCount = 0;
4824 pSMB->DataOffset = 0;
4825 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4826 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4827 pSMB->ParameterCount = pSMB->TotalParameterCount;
4828 if(notify_subdirs)
4829 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4830 pSMB->Reserved2 = 0;
4831 pSMB->CompletionFilter = cpu_to_le32(filter);
4832 pSMB->Fid = netfid; /* file handle always le */
4833 pSMB->ByteCount = 0;
4834
4835 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4836 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4837 if (rc) {
4838 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004839 } else {
4840 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004841 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004842 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004843 sizeof(struct dir_notify_req),
4844 GFP_KERNEL);
4845 if(dnotify_req) {
4846 dnotify_req->Pid = pSMB->hdr.Pid;
4847 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4848 dnotify_req->Mid = pSMB->hdr.Mid;
4849 dnotify_req->Tid = pSMB->hdr.Tid;
4850 dnotify_req->Uid = pSMB->hdr.Uid;
4851 dnotify_req->netfid = netfid;
4852 dnotify_req->pfile = pfile;
4853 dnotify_req->filter = filter;
4854 dnotify_req->multishot = multishot;
4855 spin_lock(&GlobalMid_Lock);
4856 list_add_tail(&dnotify_req->lhead,
4857 &GlobalDnotifyReqList);
4858 spin_unlock(&GlobalMid_Lock);
4859 } else
4860 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 }
4862 cifs_buf_release(pSMB);
4863 return rc;
4864}
4865#ifdef CONFIG_CIFS_XATTR
4866ssize_t
4867CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4868 const unsigned char *searchName,
4869 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004870 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871{
4872 /* BB assumes one setup word */
4873 TRANSACTION2_QPI_REQ *pSMB = NULL;
4874 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4875 int rc = 0;
4876 int bytes_returned;
4877 int name_len;
4878 struct fea * temp_fea;
4879 char * temp_ptr;
4880 __u16 params, byte_count;
4881
4882 cFYI(1, ("In Query All EAs path %s", searchName));
4883QAllEAsRetry:
4884 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4885 (void **) &pSMBr);
4886 if (rc)
4887 return rc;
4888
4889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4890 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004891 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004892 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 name_len++; /* trailing null */
4894 name_len *= 2;
4895 } else { /* BB improve the check for buffer overruns BB */
4896 name_len = strnlen(searchName, PATH_MAX);
4897 name_len++; /* trailing null */
4898 strncpy(pSMB->FileName, searchName, name_len);
4899 }
4900
4901 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4902 pSMB->TotalDataCount = 0;
4903 pSMB->MaxParameterCount = cpu_to_le16(2);
4904 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4905 pSMB->MaxSetupCount = 0;
4906 pSMB->Reserved = 0;
4907 pSMB->Flags = 0;
4908 pSMB->Timeout = 0;
4909 pSMB->Reserved2 = 0;
4910 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4911 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4912 pSMB->DataCount = 0;
4913 pSMB->DataOffset = 0;
4914 pSMB->SetupCount = 1;
4915 pSMB->Reserved3 = 0;
4916 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4917 byte_count = params + 1 /* pad */ ;
4918 pSMB->TotalParameterCount = cpu_to_le16(params);
4919 pSMB->ParameterCount = pSMB->TotalParameterCount;
4920 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4921 pSMB->Reserved4 = 0;
4922 pSMB->hdr.smb_buf_length += byte_count;
4923 pSMB->ByteCount = cpu_to_le16(byte_count);
4924
4925 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4926 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4927 if (rc) {
4928 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4929 } else { /* decode response */
4930 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4931
4932 /* BB also check enough total bytes returned */
4933 /* BB we need to improve the validity checking
4934 of these trans2 responses */
4935 if (rc || (pSMBr->ByteCount < 4))
4936 rc = -EIO; /* bad smb */
4937 /* else if (pFindData){
4938 memcpy((char *) pFindData,
4939 (char *) &pSMBr->hdr.Protocol +
4940 data_offset, kl);
4941 }*/ else {
4942 /* check that length of list is not more than bcc */
4943 /* check that each entry does not go beyond length
4944 of list */
4945 /* check that each element of each entry does not
4946 go beyond end of list */
4947 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4948 struct fealist * ea_response_data;
4949 rc = 0;
4950 /* validate_trans2_offsets() */
4951 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4952 ea_response_data = (struct fealist *)
4953 (((char *) &pSMBr->hdr.Protocol) +
4954 data_offset);
4955 name_len = le32_to_cpu(ea_response_data->list_len);
4956 cFYI(1,("ea length %d", name_len));
4957 if(name_len <= 8) {
4958 /* returned EA size zeroed at top of function */
4959 cFYI(1,("empty EA list returned from server"));
4960 } else {
4961 /* account for ea list len */
4962 name_len -= 4;
4963 temp_fea = ea_response_data->list;
4964 temp_ptr = (char *)temp_fea;
4965 while(name_len > 0) {
4966 __u16 value_len;
4967 name_len -= 4;
4968 temp_ptr += 4;
4969 rc += temp_fea->name_len;
4970 /* account for prefix user. and trailing null */
4971 rc = rc + 5 + 1;
4972 if(rc<(int)buf_size) {
4973 memcpy(EAData,"user.",5);
4974 EAData+=5;
4975 memcpy(EAData,temp_ptr,temp_fea->name_len);
4976 EAData+=temp_fea->name_len;
4977 /* null terminate name */
4978 *EAData = 0;
4979 EAData = EAData + 1;
4980 } else if(buf_size == 0) {
4981 /* skip copy - calc size only */
4982 } else {
4983 /* stop before overrun buffer */
4984 rc = -ERANGE;
4985 break;
4986 }
4987 name_len -= temp_fea->name_len;
4988 temp_ptr += temp_fea->name_len;
4989 /* account for trailing null */
4990 name_len--;
4991 temp_ptr++;
4992 value_len = le16_to_cpu(temp_fea->value_len);
4993 name_len -= value_len;
4994 temp_ptr += value_len;
4995 /* BB check that temp_ptr is still within smb BB*/
4996 /* no trailing null to account for in value len */
4997 /* go on to next EA */
4998 temp_fea = (struct fea *)temp_ptr;
4999 }
5000 }
5001 }
5002 }
5003 if (pSMB)
5004 cifs_buf_release(pSMB);
5005 if (rc == -EAGAIN)
5006 goto QAllEAsRetry;
5007
5008 return (ssize_t)rc;
5009}
5010
5011ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5012 const unsigned char * searchName,const unsigned char * ea_name,
5013 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005014 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015{
5016 TRANSACTION2_QPI_REQ *pSMB = NULL;
5017 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5018 int rc = 0;
5019 int bytes_returned;
5020 int name_len;
5021 struct fea * temp_fea;
5022 char * temp_ptr;
5023 __u16 params, byte_count;
5024
5025 cFYI(1, ("In Query EA path %s", searchName));
5026QEARetry:
5027 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5028 (void **) &pSMBr);
5029 if (rc)
5030 return rc;
5031
5032 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5033 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005034 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005035 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 name_len++; /* trailing null */
5037 name_len *= 2;
5038 } else { /* BB improve the check for buffer overruns BB */
5039 name_len = strnlen(searchName, PATH_MAX);
5040 name_len++; /* trailing null */
5041 strncpy(pSMB->FileName, searchName, name_len);
5042 }
5043
5044 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5045 pSMB->TotalDataCount = 0;
5046 pSMB->MaxParameterCount = cpu_to_le16(2);
5047 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5048 pSMB->MaxSetupCount = 0;
5049 pSMB->Reserved = 0;
5050 pSMB->Flags = 0;
5051 pSMB->Timeout = 0;
5052 pSMB->Reserved2 = 0;
5053 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5054 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5055 pSMB->DataCount = 0;
5056 pSMB->DataOffset = 0;
5057 pSMB->SetupCount = 1;
5058 pSMB->Reserved3 = 0;
5059 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5060 byte_count = params + 1 /* pad */ ;
5061 pSMB->TotalParameterCount = cpu_to_le16(params);
5062 pSMB->ParameterCount = pSMB->TotalParameterCount;
5063 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5064 pSMB->Reserved4 = 0;
5065 pSMB->hdr.smb_buf_length += byte_count;
5066 pSMB->ByteCount = cpu_to_le16(byte_count);
5067
5068 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5070 if (rc) {
5071 cFYI(1, ("Send error in Query EA = %d", rc));
5072 } else { /* decode response */
5073 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5074
5075 /* BB also check enough total bytes returned */
5076 /* BB we need to improve the validity checking
5077 of these trans2 responses */
5078 if (rc || (pSMBr->ByteCount < 4))
5079 rc = -EIO; /* bad smb */
5080 /* else if (pFindData){
5081 memcpy((char *) pFindData,
5082 (char *) &pSMBr->hdr.Protocol +
5083 data_offset, kl);
5084 }*/ else {
5085 /* check that length of list is not more than bcc */
5086 /* check that each entry does not go beyond length
5087 of list */
5088 /* check that each element of each entry does not
5089 go beyond end of list */
5090 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5091 struct fealist * ea_response_data;
5092 rc = -ENODATA;
5093 /* validate_trans2_offsets() */
5094 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5095 ea_response_data = (struct fealist *)
5096 (((char *) &pSMBr->hdr.Protocol) +
5097 data_offset);
5098 name_len = le32_to_cpu(ea_response_data->list_len);
5099 cFYI(1,("ea length %d", name_len));
5100 if(name_len <= 8) {
5101 /* returned EA size zeroed at top of function */
5102 cFYI(1,("empty EA list returned from server"));
5103 } else {
5104 /* account for ea list len */
5105 name_len -= 4;
5106 temp_fea = ea_response_data->list;
5107 temp_ptr = (char *)temp_fea;
5108 /* loop through checking if we have a matching
5109 name and then return the associated value */
5110 while(name_len > 0) {
5111 __u16 value_len;
5112 name_len -= 4;
5113 temp_ptr += 4;
5114 value_len = le16_to_cpu(temp_fea->value_len);
5115 /* BB validate that value_len falls within SMB,
5116 even though maximum for name_len is 255 */
5117 if(memcmp(temp_fea->name,ea_name,
5118 temp_fea->name_len) == 0) {
5119 /* found a match */
5120 rc = value_len;
5121 /* account for prefix user. and trailing null */
5122 if(rc<=(int)buf_size) {
5123 memcpy(ea_value,
5124 temp_fea->name+temp_fea->name_len+1,
5125 rc);
5126 /* ea values, unlike ea names,
5127 are not null terminated */
5128 } else if(buf_size == 0) {
5129 /* skip copy - calc size only */
5130 } else {
5131 /* stop before overrun buffer */
5132 rc = -ERANGE;
5133 }
5134 break;
5135 }
5136 name_len -= temp_fea->name_len;
5137 temp_ptr += temp_fea->name_len;
5138 /* account for trailing null */
5139 name_len--;
5140 temp_ptr++;
5141 name_len -= value_len;
5142 temp_ptr += value_len;
5143 /* no trailing null to account for in value len */
5144 /* go on to next EA */
5145 temp_fea = (struct fea *)temp_ptr;
5146 }
5147 }
5148 }
5149 }
5150 if (pSMB)
5151 cifs_buf_release(pSMB);
5152 if (rc == -EAGAIN)
5153 goto QEARetry;
5154
5155 return (ssize_t)rc;
5156}
5157
5158int
5159CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5160 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005161 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5162 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163{
5164 struct smb_com_transaction2_spi_req *pSMB = NULL;
5165 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5166 struct fealist *parm_data;
5167 int name_len;
5168 int rc = 0;
5169 int bytes_returned = 0;
5170 __u16 params, param_offset, byte_count, offset, count;
5171
5172 cFYI(1, ("In SetEA"));
5173SetEARetry:
5174 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5175 (void **) &pSMBr);
5176 if (rc)
5177 return rc;
5178
5179 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5180 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005181 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005182 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 name_len++; /* trailing null */
5184 name_len *= 2;
5185 } else { /* BB improve the check for buffer overruns BB */
5186 name_len = strnlen(fileName, PATH_MAX);
5187 name_len++; /* trailing null */
5188 strncpy(pSMB->FileName, fileName, name_len);
5189 }
5190
5191 params = 6 + name_len;
5192
5193 /* done calculating parms using name_len of file name,
5194 now use name_len to calculate length of ea name
5195 we are going to create in the inode xattrs */
5196 if(ea_name == NULL)
5197 name_len = 0;
5198 else
5199 name_len = strnlen(ea_name,255);
5200
5201 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5202 pSMB->MaxParameterCount = cpu_to_le16(2);
5203 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5204 pSMB->MaxSetupCount = 0;
5205 pSMB->Reserved = 0;
5206 pSMB->Flags = 0;
5207 pSMB->Timeout = 0;
5208 pSMB->Reserved2 = 0;
5209 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5210 InformationLevel) - 4;
5211 offset = param_offset + params;
5212 pSMB->InformationLevel =
5213 cpu_to_le16(SMB_SET_FILE_EA);
5214
5215 parm_data =
5216 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5217 offset);
5218 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5219 pSMB->DataOffset = cpu_to_le16(offset);
5220 pSMB->SetupCount = 1;
5221 pSMB->Reserved3 = 0;
5222 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5223 byte_count = 3 /* pad */ + params + count;
5224 pSMB->DataCount = cpu_to_le16(count);
5225 parm_data->list_len = cpu_to_le32(count);
5226 parm_data->list[0].EA_flags = 0;
5227 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005228 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 /* EA names are always ASCII */
5230 if(ea_name)
5231 strncpy(parm_data->list[0].name,ea_name,name_len);
5232 parm_data->list[0].name[name_len] = 0;
5233 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5234 /* caller ensures that ea_value_len is less than 64K but
5235 we need to ensure that it fits within the smb */
5236
5237 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5238 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5239 if(ea_value_len)
5240 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5241
5242 pSMB->TotalDataCount = pSMB->DataCount;
5243 pSMB->ParameterCount = cpu_to_le16(params);
5244 pSMB->TotalParameterCount = pSMB->ParameterCount;
5245 pSMB->Reserved4 = 0;
5246 pSMB->hdr.smb_buf_length += byte_count;
5247 pSMB->ByteCount = cpu_to_le16(byte_count);
5248 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5249 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5250 if (rc) {
5251 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5252 }
5253
5254 cifs_buf_release(pSMB);
5255
5256 if (rc == -EAGAIN)
5257 goto SetEARetry;
5258
5259 return rc;
5260}
5261
5262#endif