[CIFS] Typo in previous patch
[linux-2.6-block.git] / fs / cifs / cifssmb.c
... / ...
CommitLineData
1/*
2 * fs/cifs/cifssmb.c
3 *
4 * Copyright (C) International Business Machines Corp., 2002,2007
5 * 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 differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
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"
40#include "cifsacl.h"
41
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
47#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
49 {LANMAN2_PROT, "\2LANMAN2.1"},
50#endif /* weak password hashing for legacy clients */
51 {CIFS_PROT, "\2NT LM 0.12"},
52 {POSIX_PROT, "\2POSIX 2"},
53 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
60#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
62 {LANMAN2_PROT, "\2LANMAN2.1"},
63#endif /* weak password hashing for legacy clients */
64 {CIFS_PROT, "\2NT LM 0.12"},
65 {BAD_PROT, "\2"}
66};
67#endif
68
69/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
72#define CIFS_NUM_PROT 4
73#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
78#define CIFS_NUM_PROT 3
79#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
84
85/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
87static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
88{
89 struct cifsFileInfo *open_file = NULL;
90 struct list_head *tmp;
91 struct list_head *tmp1;
92
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
96 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
97 if (open_file) {
98 open_file->invalidHandle = TRUE;
99 }
100 }
101 write_unlock(&GlobalSMBSeslock);
102 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
103 to this tcon */
104}
105
106/* If the return code is zero, this function must fill in request_buf pointer */
107static int
108small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
109 void **request_buf /* returned */)
110{
111 int rc = 0;
112
113 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
114 check for tcp and smb session status done differently
115 for those three - in the calling routine */
116 if (tcon) {
117 if (tcon->tidStatus == CifsExiting) {
118 /* only tree disconnect, open, and write,
119 (and ulogoff which does not have tcon)
120 are allowed as we start force umount */
121 if ((smb_command != SMB_COM_WRITE_ANDX) &&
122 (smb_command != SMB_COM_OPEN_ANDX) &&
123 (smb_command != SMB_COM_TREE_DISCONNECT)) {
124 cFYI(1, ("can not send cmd %d while umounting",
125 smb_command));
126 return -ENODEV;
127 }
128 }
129 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
130 (tcon->ses->server)) {
131 struct nls_table *nls_codepage;
132 /* Give Demultiplex thread up to 10 seconds to
133 reconnect, should be greater than cifs socket
134 timeout which is 7 seconds */
135 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
137 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
138 if (tcon->ses->server->tcpStatus == CifsNeedReconnect) {
139 /* on "soft" mounts we wait once */
140 if ((tcon->retry == FALSE) ||
141 (tcon->ses->status == CifsExiting)) {
142 cFYI(1, ("gave up waiting on "
143 "reconnect in smb_init"));
144 return -EHOSTDOWN;
145 } /* else "hard" mount - keep retrying
146 until process is killed or server
147 comes back on-line */
148 } else /* TCP session is reestablished now */
149 break;
150 }
151
152 nls_codepage = load_nls_default();
153 /* need to prevent multiple threads trying to
154 simultaneously reconnect the same SMB session */
155 down(&tcon->ses->sesSem);
156 if (tcon->ses->status == CifsNeedReconnect)
157 rc = cifs_setup_session(0, tcon->ses,
158 nls_codepage);
159 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
160 mark_open_files_invalid(tcon);
161 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
162 tcon, nls_codepage);
163 up(&tcon->ses->sesSem);
164 /* tell server which Unix caps we support */
165 if (tcon->ses->capabilities & CAP_UNIX)
166 reset_cifs_unix_caps(0 /* no xid */,
167 tcon,
168 NULL /* we do not know sb */,
169 NULL /* no vol info */);
170 /* BB FIXME add code to check if wsize needs
171 update due to negotiated smb buffer size
172 shrinking */
173 if (rc == 0)
174 atomic_inc(&tconInfoReconnectCount);
175
176 cFYI(1, ("reconnect tcon rc = %d", rc));
177 /* Removed call to reopen open files here.
178 It is safer (and faster) to reopen files
179 one at a time as needed in read and write */
180
181 /* Check if handle based operation so we
182 know whether we can continue or not without
183 returning to caller to reset file handle */
184 switch (smb_command) {
185 case SMB_COM_READ_ANDX:
186 case SMB_COM_WRITE_ANDX:
187 case SMB_COM_CLOSE:
188 case SMB_COM_FIND_CLOSE2:
189 case SMB_COM_LOCKING_ANDX: {
190 unload_nls(nls_codepage);
191 return -EAGAIN;
192 }
193 }
194 } else {
195 up(&tcon->ses->sesSem);
196 }
197 unload_nls(nls_codepage);
198
199 } else {
200 return -EIO;
201 }
202 }
203 if (rc)
204 return rc;
205
206 *request_buf = cifs_small_buf_get();
207 if (*request_buf == NULL) {
208 /* BB should we add a retry in here if not a writepage? */
209 return -ENOMEM;
210 }
211
212 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
213
214 if (tcon != NULL)
215 cifs_stats_inc(&tcon->num_smbs_sent);
216
217 return rc;
218}
219
220int
221small_smb_init_no_tc(const int smb_command, const int wct,
222 struct cifsSesInfo *ses, void **request_buf)
223{
224 int rc;
225 struct smb_hdr *buffer;
226
227 rc = small_smb_init(smb_command, wct, NULL, request_buf);
228 if (rc)
229 return rc;
230
231 buffer = (struct smb_hdr *)*request_buf;
232 buffer->Mid = GetNextMid(ses->server);
233 if (ses->capabilities & CAP_UNICODE)
234 buffer->Flags2 |= SMBFLG2_UNICODE;
235 if (ses->capabilities & CAP_STATUS32)
236 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
237
238 /* uid, tid can stay at zero as set in header assemble */
239
240 /* BB add support for turning on the signing when
241 this function is used after 1st of session setup requests */
242
243 return rc;
244}
245
246/* If the return code is zero, this function must fill in request_buf pointer */
247static int
248smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
249 void **request_buf /* returned */ ,
250 void **response_buf /* returned */ )
251{
252 int rc = 0;
253
254 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
255 check for tcp and smb session status done differently
256 for those three - in the calling routine */
257 if (tcon) {
258 if (tcon->tidStatus == CifsExiting) {
259 /* only tree disconnect, open, and write,
260 (and ulogoff which does not have tcon)
261 are allowed as we start force umount */
262 if ((smb_command != SMB_COM_WRITE_ANDX) &&
263 (smb_command != SMB_COM_OPEN_ANDX) &&
264 (smb_command != SMB_COM_TREE_DISCONNECT)) {
265 cFYI(1, ("can not send cmd %d while umounting",
266 smb_command));
267 return -ENODEV;
268 }
269 }
270
271 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
272 (tcon->ses->server)) {
273 struct nls_table *nls_codepage;
274 /* Give Demultiplex thread up to 10 seconds to
275 reconnect, should be greater than cifs socket
276 timeout which is 7 seconds */
277 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
278 wait_event_interruptible_timeout(tcon->ses->server->response_q,
279 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
280 if (tcon->ses->server->tcpStatus ==
281 CifsNeedReconnect) {
282 /* on "soft" mounts we wait once */
283 if ((tcon->retry == FALSE) ||
284 (tcon->ses->status == CifsExiting)) {
285 cFYI(1, ("gave up waiting on "
286 "reconnect in smb_init"));
287 return -EHOSTDOWN;
288 } /* else "hard" mount - keep retrying
289 until process is killed or server
290 comes on-line */
291 } else /* TCP session is reestablished now */
292 break;
293 }
294 nls_codepage = load_nls_default();
295 /* need to prevent multiple threads trying to
296 simultaneously reconnect the same SMB session */
297 down(&tcon->ses->sesSem);
298 if (tcon->ses->status == CifsNeedReconnect)
299 rc = cifs_setup_session(0, tcon->ses,
300 nls_codepage);
301 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
302 mark_open_files_invalid(tcon);
303 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
304 tcon, nls_codepage);
305 up(&tcon->ses->sesSem);
306 /* tell server which Unix caps we support */
307 if (tcon->ses->capabilities & CAP_UNIX)
308 reset_cifs_unix_caps(0 /* no xid */,
309 tcon,
310 NULL /* do not know sb */,
311 NULL /* no vol info */);
312 /* BB FIXME add code to check if wsize needs
313 update due to negotiated smb buffer size
314 shrinking */
315 if (rc == 0)
316 atomic_inc(&tconInfoReconnectCount);
317
318 cFYI(1, ("reconnect tcon rc = %d", rc));
319 /* Removed call to reopen open files here.
320 It is safer (and faster) to reopen files
321 one at a time as needed in read and write */
322
323 /* Check if handle based operation so we
324 know whether we can continue or not without
325 returning to caller to reset file handle */
326 switch (smb_command) {
327 case SMB_COM_READ_ANDX:
328 case SMB_COM_WRITE_ANDX:
329 case SMB_COM_CLOSE:
330 case SMB_COM_FIND_CLOSE2:
331 case SMB_COM_LOCKING_ANDX: {
332 unload_nls(nls_codepage);
333 return -EAGAIN;
334 }
335 }
336 } else {
337 up(&tcon->ses->sesSem);
338 }
339 unload_nls(nls_codepage);
340
341 } else {
342 return -EIO;
343 }
344 }
345 if (rc)
346 return rc;
347
348 *request_buf = cifs_buf_get();
349 if (*request_buf == NULL) {
350 /* BB should we add a retry in here if not a writepage? */
351 return -ENOMEM;
352 }
353 /* Although the original thought was we needed the response buf for */
354 /* potential retries of smb operations it turns out we can determine */
355 /* from the mid flags when the request buffer can be resent without */
356 /* having to use a second distinct buffer for the response */
357 if (response_buf)
358 *response_buf = *request_buf;
359
360 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
361 wct /*wct */ );
362
363 if (tcon != NULL)
364 cifs_stats_inc(&tcon->num_smbs_sent);
365
366 return rc;
367}
368
369static int validate_t2(struct smb_t2_rsp *pSMB)
370{
371 int rc = -EINVAL;
372 int total_size;
373 char *pBCC;
374
375 /* check for plausible wct, bcc and t2 data and parm sizes */
376 /* check for parm and data offset going beyond end of smb */
377 if (pSMB->hdr.WordCount >= 10) {
378 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
379 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
380 /* check that bcc is at least as big as parms + data */
381 /* check that bcc is less than negotiated smb buffer */
382 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
383 if (total_size < 512) {
384 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
385 /* BCC le converted in SendReceive */
386 pBCC = (pSMB->hdr.WordCount * 2) +
387 sizeof(struct smb_hdr) +
388 (char *)pSMB;
389 if ((total_size <= (*(u16 *)pBCC)) &&
390 (total_size <
391 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
392 return 0;
393 }
394 }
395 }
396 }
397 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
398 sizeof(struct smb_t2_rsp) + 16);
399 return rc;
400}
401int
402CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
403{
404 NEGOTIATE_REQ *pSMB;
405 NEGOTIATE_RSP *pSMBr;
406 int rc = 0;
407 int bytes_returned;
408 int i;
409 struct TCP_Server_Info *server;
410 u16 count;
411 unsigned int secFlags;
412 u16 dialect;
413
414 if (ses->server)
415 server = ses->server;
416 else {
417 rc = -EIO;
418 return rc;
419 }
420 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
421 (void **) &pSMB, (void **) &pSMBr);
422 if (rc)
423 return rc;
424
425 /* if any of auth flags (ie not sign or seal) are overriden use them */
426 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
427 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
428 else /* if override flags set only sign/seal OR them with global auth */
429 secFlags = extended_security | ses->overrideSecFlg;
430
431 cFYI(1, ("secFlags 0x%x", secFlags));
432
433 pSMB->hdr.Mid = GetNextMid(server);
434 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
435 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
436 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
437
438 count = 0;
439 for (i = 0; i < CIFS_NUM_PROT; i++) {
440 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
441 count += strlen(protocols[i].name) + 1;
442 /* null at end of source and target buffers anyway */
443 }
444 pSMB->hdr.smb_buf_length += count;
445 pSMB->ByteCount = cpu_to_le16(count);
446
447 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
448 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
449 if (rc != 0)
450 goto neg_err_exit;
451
452 dialect = le16_to_cpu(pSMBr->DialectIndex);
453 cFYI(1, ("Dialect: %d", dialect));
454 /* Check wct = 1 error case */
455 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
456 /* core returns wct = 1, but we do not ask for core - otherwise
457 small wct just comes when dialect index is -1 indicating we
458 could not negotiate a common dialect */
459 rc = -EOPNOTSUPP;
460 goto neg_err_exit;
461#ifdef CONFIG_CIFS_WEAK_PW_HASH
462 } else if ((pSMBr->hdr.WordCount == 13)
463 && ((dialect == LANMAN_PROT)
464 || (dialect == LANMAN2_PROT))) {
465 __s16 tmp;
466 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
467
468 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
469 (secFlags & CIFSSEC_MAY_PLNTXT))
470 server->secType = LANMAN;
471 else {
472 cERROR(1, ("mount failed weak security disabled"
473 " in /proc/fs/cifs/SecurityFlags"));
474 rc = -EOPNOTSUPP;
475 goto neg_err_exit;
476 }
477 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
478 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
479 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
480 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
481 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
482 /* even though we do not use raw we might as well set this
483 accurately, in case we ever find a need for it */
484 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
485 server->maxRw = 0xFF00;
486 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
487 } else {
488 server->maxRw = 0;/* we do not need to use raw anyway */
489 server->capabilities = CAP_MPX_MODE;
490 }
491 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
492 if (tmp == -1) {
493 /* OS/2 often does not set timezone therefore
494 * we must use server time to calc time zone.
495 * Could deviate slightly from the right zone.
496 * Smallest defined timezone difference is 15 minutes
497 * (i.e. Nepal). Rounding up/down is done to match
498 * this requirement.
499 */
500 int val, seconds, remain, result;
501 struct timespec ts, utc;
502 utc = CURRENT_TIME;
503 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
504 le16_to_cpu(rsp->SrvTime.Time));
505 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
506 (int)ts.tv_sec, (int)utc.tv_sec,
507 (int)(utc.tv_sec - ts.tv_sec)));
508 val = (int)(utc.tv_sec - ts.tv_sec);
509 seconds = val < 0 ? -val : val;
510 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
511 remain = seconds % MIN_TZ_ADJ;
512 if (remain >= (MIN_TZ_ADJ / 2))
513 result += MIN_TZ_ADJ;
514 if (val < 0)
515 result = - result;
516 server->timeAdj = result;
517 } else {
518 server->timeAdj = (int)tmp;
519 server->timeAdj *= 60; /* also in seconds */
520 }
521 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
522
523
524 /* BB get server time for time conversions and add
525 code to use it and timezone since this is not UTC */
526
527 if (rsp->EncryptionKeyLength ==
528 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
529 memcpy(server->cryptKey, rsp->EncryptionKey,
530 CIFS_CRYPTO_KEY_SIZE);
531 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
532 rc = -EIO; /* need cryptkey unless plain text */
533 goto neg_err_exit;
534 }
535
536 cFYI(1, ("LANMAN negotiated"));
537 /* we will not end up setting signing flags - as no signing
538 was in LANMAN and server did not return the flags on */
539 goto signing_check;
540#else /* weak security disabled */
541 } else if (pSMBr->hdr.WordCount == 13) {
542 cERROR(1, ("mount failed, cifs module not built "
543 "with CIFS_WEAK_PW_HASH support"));
544 rc = -EOPNOTSUPP;
545#endif /* WEAK_PW_HASH */
546 goto neg_err_exit;
547 } else if (pSMBr->hdr.WordCount != 17) {
548 /* unknown wct */
549 rc = -EOPNOTSUPP;
550 goto neg_err_exit;
551 }
552 /* else wct == 17 NTLM */
553 server->secMode = pSMBr->SecurityMode;
554 if ((server->secMode & SECMODE_USER) == 0)
555 cFYI(1, ("share mode security"));
556
557 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
558#ifdef CONFIG_CIFS_WEAK_PW_HASH
559 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
560#endif /* CIFS_WEAK_PW_HASH */
561 cERROR(1, ("Server requests plain text password"
562 " but client support disabled"));
563
564 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
565 server->secType = NTLMv2;
566 else if (secFlags & CIFSSEC_MAY_NTLM)
567 server->secType = NTLM;
568 else if (secFlags & CIFSSEC_MAY_NTLMV2)
569 server->secType = NTLMv2;
570 /* else krb5 ... any others ... */
571
572 /* one byte, so no need to convert this or EncryptionKeyLen from
573 little endian */
574 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
575 /* probably no need to store and check maxvcs */
576 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
577 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
578 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
579 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
580 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
581 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
582 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
583 server->timeAdj *= 60;
584 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
585 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
586 CIFS_CRYPTO_KEY_SIZE);
587 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
588 && (pSMBr->EncryptionKeyLength == 0)) {
589 /* decode security blob */
590 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
591 rc = -EIO; /* no crypt key only if plain text pwd */
592 goto neg_err_exit;
593 }
594
595 /* BB might be helpful to save off the domain of server here */
596
597 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
598 (server->capabilities & CAP_EXTENDED_SECURITY)) {
599 count = pSMBr->ByteCount;
600 if (count < 16)
601 rc = -EIO;
602 else if (count == 16) {
603 server->secType = RawNTLMSSP;
604 if (server->socketUseCount.counter > 1) {
605 if (memcmp(server->server_GUID,
606 pSMBr->u.extended_response.
607 GUID, 16) != 0) {
608 cFYI(1, ("server UID changed"));
609 memcpy(server->server_GUID,
610 pSMBr->u.extended_response.GUID,
611 16);
612 }
613 } else
614 memcpy(server->server_GUID,
615 pSMBr->u.extended_response.GUID, 16);
616 } else {
617 rc = decode_negTokenInit(pSMBr->u.extended_response.
618 SecurityBlob,
619 count - 16,
620 &server->secType);
621 if (rc == 1) {
622 /* BB Need to fill struct for sessetup here */
623 rc = -EOPNOTSUPP;
624 } else {
625 rc = -EINVAL;
626 }
627 }
628 } else
629 server->capabilities &= ~CAP_EXTENDED_SECURITY;
630
631#ifdef CONFIG_CIFS_WEAK_PW_HASH
632signing_check:
633#endif
634 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
635 /* MUST_SIGN already includes the MAY_SIGN FLAG
636 so if this is zero it means that signing is disabled */
637 cFYI(1, ("Signing disabled"));
638 if (server->secMode & SECMODE_SIGN_REQUIRED)
639 cERROR(1, ("Server requires "
640 "/proc/fs/cifs/PacketSigningEnabled "
641 "to be on"));
642 server->secMode &=
643 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
644 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
645 /* signing required */
646 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
647 if ((server->secMode &
648 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
649 cERROR(1,
650 ("signing required but server lacks support"));
651 rc = -EOPNOTSUPP;
652 } else
653 server->secMode |= SECMODE_SIGN_REQUIRED;
654 } else {
655 /* signing optional ie CIFSSEC_MAY_SIGN */
656 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
657 server->secMode &=
658 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
659 }
660
661neg_err_exit:
662 cifs_buf_release(pSMB);
663
664 cFYI(1, ("negprot rc %d", rc));
665 return rc;
666}
667
668int
669CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
670{
671 struct smb_hdr *smb_buffer;
672 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
673 int rc = 0;
674 int length;
675
676 cFYI(1, ("In tree disconnect"));
677 /*
678 * If last user of the connection and
679 * connection alive - disconnect it
680 * If this is the last connection on the server session disconnect it
681 * (and inside session disconnect we should check if tcp socket needs
682 * to be freed and kernel thread woken up).
683 */
684 if (tcon)
685 down(&tcon->tconSem);
686 else
687 return -EIO;
688
689 atomic_dec(&tcon->useCount);
690 if (atomic_read(&tcon->useCount) > 0) {
691 up(&tcon->tconSem);
692 return -EBUSY;
693 }
694
695 /* No need to return error on this operation if tid invalidated and
696 closed on server already e.g. due to tcp session crashing */
697 if (tcon->tidStatus == CifsNeedReconnect) {
698 up(&tcon->tconSem);
699 return 0;
700 }
701
702 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
703 up(&tcon->tconSem);
704 return -EIO;
705 }
706 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
707 (void **)&smb_buffer);
708 if (rc) {
709 up(&tcon->tconSem);
710 return rc;
711 } else {
712 smb_buffer_response = smb_buffer; /* BB removeme BB */
713 }
714 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
715 &length, 0);
716 if (rc)
717 cFYI(1, ("Tree disconnect failed %d", rc));
718
719 if (smb_buffer)
720 cifs_small_buf_release(smb_buffer);
721 up(&tcon->tconSem);
722
723 /* No need to return error on this operation if tid invalidated and
724 closed on server already e.g. due to tcp session crashing */
725 if (rc == -EAGAIN)
726 rc = 0;
727
728 return rc;
729}
730
731int
732CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
733{
734 struct smb_hdr *smb_buffer_response;
735 LOGOFF_ANDX_REQ *pSMB;
736 int rc = 0;
737 int length;
738
739 cFYI(1, ("In SMBLogoff for session disconnect"));
740 if (ses)
741 down(&ses->sesSem);
742 else
743 return -EIO;
744
745 atomic_dec(&ses->inUse);
746 if (atomic_read(&ses->inUse) > 0) {
747 up(&ses->sesSem);
748 return -EBUSY;
749 }
750 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
751 if (rc) {
752 up(&ses->sesSem);
753 return rc;
754 }
755
756 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
757
758 if (ses->server) {
759 pSMB->hdr.Mid = GetNextMid(ses->server);
760
761 if (ses->server->secMode &
762 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
763 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
764 }
765
766 pSMB->hdr.Uid = ses->Suid;
767
768 pSMB->AndXCommand = 0xFF;
769 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
770 smb_buffer_response, &length, 0);
771 if (ses->server) {
772 atomic_dec(&ses->server->socketUseCount);
773 if (atomic_read(&ses->server->socketUseCount) == 0) {
774 spin_lock(&GlobalMid_Lock);
775 ses->server->tcpStatus = CifsExiting;
776 spin_unlock(&GlobalMid_Lock);
777 rc = -ESHUTDOWN;
778 }
779 }
780 up(&ses->sesSem);
781 cifs_small_buf_release(pSMB);
782
783 /* if session dead then we do not need to do ulogoff,
784 since server closed smb session, no sense reporting
785 error */
786 if (rc == -EAGAIN)
787 rc = 0;
788 return rc;
789}
790
791int
792CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
793 __u16 type, const struct nls_table *nls_codepage, int remap)
794{
795 TRANSACTION2_SPI_REQ *pSMB = NULL;
796 TRANSACTION2_SPI_RSP *pSMBr = NULL;
797 struct unlink_psx_rq *pRqD;
798 int name_len;
799 int rc = 0;
800 int bytes_returned = 0;
801 __u16 params, param_offset, offset, byte_count;
802
803 cFYI(1, ("In POSIX delete"));
804PsxDelete:
805 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
806 (void **) &pSMBr);
807 if (rc)
808 return rc;
809
810 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
811 name_len =
812 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
813 PATH_MAX, nls_codepage, remap);
814 name_len++; /* trailing null */
815 name_len *= 2;
816 } else { /* BB add path length overrun check */
817 name_len = strnlen(fileName, PATH_MAX);
818 name_len++; /* trailing null */
819 strncpy(pSMB->FileName, fileName, name_len);
820 }
821
822 params = 6 + name_len;
823 pSMB->MaxParameterCount = cpu_to_le16(2);
824 pSMB->MaxDataCount = 0; /* BB double check this with jra */
825 pSMB->MaxSetupCount = 0;
826 pSMB->Reserved = 0;
827 pSMB->Flags = 0;
828 pSMB->Timeout = 0;
829 pSMB->Reserved2 = 0;
830 param_offset = offsetof(struct smb_com_transaction2_spi_req,
831 InformationLevel) - 4;
832 offset = param_offset + params;
833
834 /* Setup pointer to Request Data (inode type) */
835 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
836 pRqD->type = cpu_to_le16(type);
837 pSMB->ParameterOffset = cpu_to_le16(param_offset);
838 pSMB->DataOffset = cpu_to_le16(offset);
839 pSMB->SetupCount = 1;
840 pSMB->Reserved3 = 0;
841 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
842 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
843
844 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
845 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
846 pSMB->ParameterCount = cpu_to_le16(params);
847 pSMB->TotalParameterCount = pSMB->ParameterCount;
848 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
849 pSMB->Reserved4 = 0;
850 pSMB->hdr.smb_buf_length += byte_count;
851 pSMB->ByteCount = cpu_to_le16(byte_count);
852 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
853 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
854 if (rc) {
855 cFYI(1, ("Posix delete returned %d", rc));
856 }
857 cifs_buf_release(pSMB);
858
859 cifs_stats_inc(&tcon->num_deletes);
860
861 if (rc == -EAGAIN)
862 goto PsxDelete;
863
864 return rc;
865}
866
867int
868CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
869 const struct nls_table *nls_codepage, int remap)
870{
871 DELETE_FILE_REQ *pSMB = NULL;
872 DELETE_FILE_RSP *pSMBr = NULL;
873 int rc = 0;
874 int bytes_returned;
875 int name_len;
876
877DelFileRetry:
878 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
879 (void **) &pSMBr);
880 if (rc)
881 return rc;
882
883 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
884 name_len =
885 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
886 PATH_MAX, nls_codepage, remap);
887 name_len++; /* trailing null */
888 name_len *= 2;
889 } else { /* BB improve check for buffer overruns BB */
890 name_len = strnlen(fileName, PATH_MAX);
891 name_len++; /* trailing null */
892 strncpy(pSMB->fileName, fileName, name_len);
893 }
894 pSMB->SearchAttributes =
895 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
896 pSMB->BufferFormat = 0x04;
897 pSMB->hdr.smb_buf_length += name_len + 1;
898 pSMB->ByteCount = cpu_to_le16(name_len + 1);
899 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
900 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
901 cifs_stats_inc(&tcon->num_deletes);
902 if (rc) {
903 cFYI(1, ("Error in RMFile = %d", rc));
904 }
905
906 cifs_buf_release(pSMB);
907 if (rc == -EAGAIN)
908 goto DelFileRetry;
909
910 return rc;
911}
912
913int
914CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
915 const struct nls_table *nls_codepage, int remap)
916{
917 DELETE_DIRECTORY_REQ *pSMB = NULL;
918 DELETE_DIRECTORY_RSP *pSMBr = NULL;
919 int rc = 0;
920 int bytes_returned;
921 int name_len;
922
923 cFYI(1, ("In CIFSSMBRmDir"));
924RmDirRetry:
925 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
926 (void **) &pSMBr);
927 if (rc)
928 return rc;
929
930 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
931 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
932 PATH_MAX, nls_codepage, remap);
933 name_len++; /* trailing null */
934 name_len *= 2;
935 } else { /* BB improve check for buffer overruns BB */
936 name_len = strnlen(dirName, PATH_MAX);
937 name_len++; /* trailing null */
938 strncpy(pSMB->DirName, dirName, name_len);
939 }
940
941 pSMB->BufferFormat = 0x04;
942 pSMB->hdr.smb_buf_length += name_len + 1;
943 pSMB->ByteCount = cpu_to_le16(name_len + 1);
944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
946 cifs_stats_inc(&tcon->num_rmdirs);
947 if (rc) {
948 cFYI(1, ("Error in RMDir = %d", rc));
949 }
950
951 cifs_buf_release(pSMB);
952 if (rc == -EAGAIN)
953 goto RmDirRetry;
954 return rc;
955}
956
957int
958CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
959 const char *name, const struct nls_table *nls_codepage, int remap)
960{
961 int rc = 0;
962 CREATE_DIRECTORY_REQ *pSMB = NULL;
963 CREATE_DIRECTORY_RSP *pSMBr = NULL;
964 int bytes_returned;
965 int name_len;
966
967 cFYI(1, ("In CIFSSMBMkDir"));
968MkDirRetry:
969 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
970 (void **) &pSMBr);
971 if (rc)
972 return rc;
973
974 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
975 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
976 PATH_MAX, nls_codepage, remap);
977 name_len++; /* trailing null */
978 name_len *= 2;
979 } else { /* BB improve check for buffer overruns BB */
980 name_len = strnlen(name, PATH_MAX);
981 name_len++; /* trailing null */
982 strncpy(pSMB->DirName, name, name_len);
983 }
984
985 pSMB->BufferFormat = 0x04;
986 pSMB->hdr.smb_buf_length += name_len + 1;
987 pSMB->ByteCount = cpu_to_le16(name_len + 1);
988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
990 cifs_stats_inc(&tcon->num_mkdirs);
991 if (rc) {
992 cFYI(1, ("Error in Mkdir = %d", rc));
993 }
994
995 cifs_buf_release(pSMB);
996 if (rc == -EAGAIN)
997 goto MkDirRetry;
998 return rc;
999}
1000
1001int
1002CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1003 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
1004 __u32 *pOplock, const char *name,
1005 const struct nls_table *nls_codepage, int remap)
1006{
1007 TRANSACTION2_SPI_REQ *pSMB = NULL;
1008 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1009 int name_len;
1010 int rc = 0;
1011 int bytes_returned = 0;
1012 __u16 params, param_offset, offset, byte_count, count;
1013 OPEN_PSX_REQ * pdata;
1014 OPEN_PSX_RSP * psx_rsp;
1015
1016 cFYI(1, ("In POSIX Create"));
1017PsxCreat:
1018 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1019 (void **) &pSMBr);
1020 if (rc)
1021 return rc;
1022
1023 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1024 name_len =
1025 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1026 PATH_MAX, nls_codepage, remap);
1027 name_len++; /* trailing null */
1028 name_len *= 2;
1029 } else { /* BB improve the check for buffer overruns BB */
1030 name_len = strnlen(name, PATH_MAX);
1031 name_len++; /* trailing null */
1032 strncpy(pSMB->FileName, name, name_len);
1033 }
1034
1035 params = 6 + name_len;
1036 count = sizeof(OPEN_PSX_REQ);
1037 pSMB->MaxParameterCount = cpu_to_le16(2);
1038 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1039 pSMB->MaxSetupCount = 0;
1040 pSMB->Reserved = 0;
1041 pSMB->Flags = 0;
1042 pSMB->Timeout = 0;
1043 pSMB->Reserved2 = 0;
1044 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1045 InformationLevel) - 4;
1046 offset = param_offset + params;
1047 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1048 pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
1049 pdata->Permissions = cpu_to_le64(mode);
1050 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1051 pdata->OpenFlags = cpu_to_le32(*pOplock);
1052 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1053 pSMB->DataOffset = cpu_to_le16(offset);
1054 pSMB->SetupCount = 1;
1055 pSMB->Reserved3 = 0;
1056 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1057 byte_count = 3 /* pad */ + params + count;
1058
1059 pSMB->DataCount = cpu_to_le16(count);
1060 pSMB->ParameterCount = cpu_to_le16(params);
1061 pSMB->TotalDataCount = pSMB->DataCount;
1062 pSMB->TotalParameterCount = pSMB->ParameterCount;
1063 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1064 pSMB->Reserved4 = 0;
1065 pSMB->hdr.smb_buf_length += byte_count;
1066 pSMB->ByteCount = cpu_to_le16(byte_count);
1067 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1068 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1069 if (rc) {
1070 cFYI(1, ("Posix create returned %d", rc));
1071 goto psx_create_err;
1072 }
1073
1074 cFYI(1, ("copying inode info"));
1075 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1076
1077 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1078 rc = -EIO; /* bad smb */
1079 goto psx_create_err;
1080 }
1081
1082 /* copy return information to pRetData */
1083 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1084 + le16_to_cpu(pSMBr->t2.DataOffset));
1085
1086 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1087 if (netfid)
1088 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1089 /* Let caller know file was created so we can set the mode. */
1090 /* Do we care about the CreateAction in any other cases? */
1091 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1092 *pOplock |= CIFS_CREATE_ACTION;
1093 /* check to make sure response data is there */
1094 if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
1095 pRetData->Type = -1; /* unknown */
1096#ifdef CONFIG_CIFS_DEBUG2
1097 cFYI(1, ("unknown type"));
1098#endif
1099 } else {
1100 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1101 + sizeof(FILE_UNIX_BASIC_INFO)) {
1102 cERROR(1, ("Open response data too small"));
1103 pRetData->Type = -1;
1104 goto psx_create_err;
1105 }
1106 memcpy((char *) pRetData,
1107 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1108 sizeof (FILE_UNIX_BASIC_INFO));
1109 }
1110
1111psx_create_err:
1112 cifs_buf_release(pSMB);
1113
1114 cifs_stats_inc(&tcon->num_mkdirs);
1115
1116 if (rc == -EAGAIN)
1117 goto PsxCreat;
1118
1119 return rc;
1120}
1121
1122static __u16 convert_disposition(int disposition)
1123{
1124 __u16 ofun = 0;
1125
1126 switch (disposition) {
1127 case FILE_SUPERSEDE:
1128 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1129 break;
1130 case FILE_OPEN:
1131 ofun = SMBOPEN_OAPPEND;
1132 break;
1133 case FILE_CREATE:
1134 ofun = SMBOPEN_OCREATE;
1135 break;
1136 case FILE_OPEN_IF:
1137 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1138 break;
1139 case FILE_OVERWRITE:
1140 ofun = SMBOPEN_OTRUNC;
1141 break;
1142 case FILE_OVERWRITE_IF:
1143 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1144 break;
1145 default:
1146 cFYI(1, ("unknown disposition %d", disposition));
1147 ofun = SMBOPEN_OAPPEND; /* regular open */
1148 }
1149 return ofun;
1150}
1151
1152int
1153SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1154 const char *fileName, const int openDisposition,
1155 const int access_flags, const int create_options, __u16 * netfid,
1156 int *pOplock, FILE_ALL_INFO * pfile_info,
1157 const struct nls_table *nls_codepage, int remap)
1158{
1159 int rc = -EACCES;
1160 OPENX_REQ *pSMB = NULL;
1161 OPENX_RSP *pSMBr = NULL;
1162 int bytes_returned;
1163 int name_len;
1164 __u16 count;
1165
1166OldOpenRetry:
1167 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1168 (void **) &pSMBr);
1169 if (rc)
1170 return rc;
1171
1172 pSMB->AndXCommand = 0xFF; /* none */
1173
1174 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1175 count = 1; /* account for one byte pad to word boundary */
1176 name_len =
1177 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1178 fileName, PATH_MAX, nls_codepage, remap);
1179 name_len++; /* trailing null */
1180 name_len *= 2;
1181 } else { /* BB improve check for buffer overruns BB */
1182 count = 0; /* no pad */
1183 name_len = strnlen(fileName, PATH_MAX);
1184 name_len++; /* trailing null */
1185 strncpy(pSMB->fileName, fileName, name_len);
1186 }
1187 if (*pOplock & REQ_OPLOCK)
1188 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1189 else if (*pOplock & REQ_BATCHOPLOCK) {
1190 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1191 }
1192 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1193 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1194 /* 0 = read
1195 1 = write
1196 2 = rw
1197 3 = execute
1198 */
1199 pSMB->Mode = cpu_to_le16(2);
1200 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1201 /* set file as system file if special file such
1202 as fifo and server expecting SFU style and
1203 no Unix extensions */
1204
1205 if (create_options & CREATE_OPTION_SPECIAL)
1206 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1207 else
1208 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
1209
1210 /* if ((omode & S_IWUGO) == 0)
1211 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1212 /* Above line causes problems due to vfs splitting create into two
1213 pieces - need to set mode after file created not while it is
1214 being created */
1215
1216 /* BB FIXME BB */
1217/* pSMB->CreateOptions = cpu_to_le32(create_options &
1218 CREATE_OPTIONS_MASK); */
1219 /* BB FIXME END BB */
1220
1221 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1222 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1223 count += name_len;
1224 pSMB->hdr.smb_buf_length += count;
1225
1226 pSMB->ByteCount = cpu_to_le16(count);
1227 /* long_op set to 1 to allow for oplock break timeouts */
1228 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1229 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1230 cifs_stats_inc(&tcon->num_opens);
1231 if (rc) {
1232 cFYI(1, ("Error in Open = %d", rc));
1233 } else {
1234 /* BB verify if wct == 15 */
1235
1236/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1237
1238 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1239 /* Let caller know file was created so we can set the mode. */
1240 /* Do we care about the CreateAction in any other cases? */
1241 /* BB FIXME BB */
1242/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1243 *pOplock |= CIFS_CREATE_ACTION; */
1244 /* BB FIXME END */
1245
1246 if (pfile_info) {
1247 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1248 pfile_info->LastAccessTime = 0; /* BB fixme */
1249 pfile_info->LastWriteTime = 0; /* BB fixme */
1250 pfile_info->ChangeTime = 0; /* BB fixme */
1251 pfile_info->Attributes =
1252 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1253 /* the file_info buf is endian converted by caller */
1254 pfile_info->AllocationSize =
1255 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1256 pfile_info->EndOfFile = pfile_info->AllocationSize;
1257 pfile_info->NumberOfLinks = cpu_to_le32(1);
1258 }
1259 }
1260
1261 cifs_buf_release(pSMB);
1262 if (rc == -EAGAIN)
1263 goto OldOpenRetry;
1264 return rc;
1265}
1266
1267int
1268CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1269 const char *fileName, const int openDisposition,
1270 const int access_flags, const int create_options, __u16 * netfid,
1271 int *pOplock, FILE_ALL_INFO * pfile_info,
1272 const struct nls_table *nls_codepage, int remap)
1273{
1274 int rc = -EACCES;
1275 OPEN_REQ *pSMB = NULL;
1276 OPEN_RSP *pSMBr = NULL;
1277 int bytes_returned;
1278 int name_len;
1279 __u16 count;
1280
1281openRetry:
1282 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1283 (void **) &pSMBr);
1284 if (rc)
1285 return rc;
1286
1287 pSMB->AndXCommand = 0xFF; /* none */
1288
1289 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1290 count = 1; /* account for one byte pad to word boundary */
1291 name_len =
1292 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1293 fileName, PATH_MAX, nls_codepage, remap);
1294 name_len++; /* trailing null */
1295 name_len *= 2;
1296 pSMB->NameLength = cpu_to_le16(name_len);
1297 } else { /* BB improve check for buffer overruns BB */
1298 count = 0; /* no pad */
1299 name_len = strnlen(fileName, PATH_MAX);
1300 name_len++; /* trailing null */
1301 pSMB->NameLength = cpu_to_le16(name_len);
1302 strncpy(pSMB->fileName, fileName, name_len);
1303 }
1304 if (*pOplock & REQ_OPLOCK)
1305 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1306 else if (*pOplock & REQ_BATCHOPLOCK) {
1307 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1308 }
1309 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1310 pSMB->AllocationSize = 0;
1311 /* set file as system file if special file such
1312 as fifo and server expecting SFU style and
1313 no Unix extensions */
1314 if (create_options & CREATE_OPTION_SPECIAL)
1315 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1316 else
1317 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1318 /* XP does not handle ATTR_POSIX_SEMANTICS */
1319 /* but it helps speed up case sensitive checks for other
1320 servers such as Samba */
1321 if (tcon->ses->capabilities & CAP_UNIX)
1322 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1323
1324 /* if ((omode & S_IWUGO) == 0)
1325 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1326 /* Above line causes problems due to vfs splitting create into two
1327 pieces - need to set mode after file created not while it is
1328 being created */
1329 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1330 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
1331 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1332 /* BB Expirement with various impersonation levels and verify */
1333 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1334 pSMB->SecurityFlags =
1335 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1336
1337 count += name_len;
1338 pSMB->hdr.smb_buf_length += count;
1339
1340 pSMB->ByteCount = cpu_to_le16(count);
1341 /* long_op set to 1 to allow for oplock break timeouts */
1342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1343 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1344 cifs_stats_inc(&tcon->num_opens);
1345 if (rc) {
1346 cFYI(1, ("Error in Open = %d", rc));
1347 } else {
1348 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1349 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1350 /* Let caller know file was created so we can set the mode. */
1351 /* Do we care about the CreateAction in any other cases? */
1352 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1353 *pOplock |= CIFS_CREATE_ACTION;
1354 if (pfile_info) {
1355 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1356 36 /* CreationTime to Attributes */);
1357 /* the file_info buf is endian converted by caller */
1358 pfile_info->AllocationSize = pSMBr->AllocationSize;
1359 pfile_info->EndOfFile = pSMBr->EndOfFile;
1360 pfile_info->NumberOfLinks = cpu_to_le32(1);
1361 }
1362 }
1363
1364 cifs_buf_release(pSMB);
1365 if (rc == -EAGAIN)
1366 goto openRetry;
1367 return rc;
1368}
1369
1370int
1371CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1372 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1373 char **buf, int *pbuf_type)
1374{
1375 int rc = -EACCES;
1376 READ_REQ *pSMB = NULL;
1377 READ_RSP *pSMBr = NULL;
1378 char *pReadData = NULL;
1379 int wct;
1380 int resp_buf_type = 0;
1381 struct kvec iov[1];
1382
1383 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1384 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1385 wct = 12;
1386 else
1387 wct = 10; /* old style read */
1388
1389 *nbytes = 0;
1390 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1391 if (rc)
1392 return rc;
1393
1394 /* tcon and ses pointer are checked in smb_init */
1395 if (tcon->ses->server == NULL)
1396 return -ECONNABORTED;
1397
1398 pSMB->AndXCommand = 0xFF; /* none */
1399 pSMB->Fid = netfid;
1400 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
1401 if (wct == 12)
1402 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
1403 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
1404 return -EIO;
1405
1406 pSMB->Remaining = 0;
1407 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1408 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
1409 if (wct == 12)
1410 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1411 else {
1412 /* old style read */
1413 struct smb_com_readx_req *pSMBW =
1414 (struct smb_com_readx_req *)pSMB;
1415 pSMBW->ByteCount = 0;
1416 }
1417
1418 iov[0].iov_base = (char *)pSMB;
1419 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1420 rc = SendReceive2(xid, tcon->ses, iov,
1421 1 /* num iovecs */,
1422 &resp_buf_type, 0);
1423 cifs_stats_inc(&tcon->num_reads);
1424 pSMBr = (READ_RSP *)iov[0].iov_base;
1425 if (rc) {
1426 cERROR(1, ("Send error in read = %d", rc));
1427 } else {
1428 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1429 data_length = data_length << 16;
1430 data_length += le16_to_cpu(pSMBr->DataLength);
1431 *nbytes = data_length;
1432
1433 /*check that DataLength would not go beyond end of SMB */
1434 if ((data_length > CIFSMaxBufSize)
1435 || (data_length > count)) {
1436 cFYI(1, ("bad length %d for count %d",
1437 data_length, count));
1438 rc = -EIO;
1439 *nbytes = 0;
1440 } else {
1441 pReadData = (char *) (&pSMBr->hdr.Protocol) +
1442 le16_to_cpu(pSMBr->DataOffset);
1443/* if (rc = copy_to_user(buf, pReadData, data_length)) {
1444 cERROR(1,("Faulting on read rc = %d",rc));
1445 rc = -EFAULT;
1446 }*/ /* can not use copy_to_user when using page cache*/
1447 if (*buf)
1448 memcpy(*buf, pReadData, data_length);
1449 }
1450 }
1451
1452/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1453 if (*buf) {
1454 if (resp_buf_type == CIFS_SMALL_BUFFER)
1455 cifs_small_buf_release(iov[0].iov_base);
1456 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1457 cifs_buf_release(iov[0].iov_base);
1458 } else if (resp_buf_type != CIFS_NO_BUFFER) {
1459 /* return buffer to caller to free */
1460 *buf = iov[0].iov_base;
1461 if (resp_buf_type == CIFS_SMALL_BUFFER)
1462 *pbuf_type = CIFS_SMALL_BUFFER;
1463 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1464 *pbuf_type = CIFS_LARGE_BUFFER;
1465 } /* else no valid buffer on return - leave as null */
1466
1467 /* Note: On -EAGAIN error only caller can retry on handle based calls
1468 since file handle passed in no longer valid */
1469 return rc;
1470}
1471
1472
1473int
1474CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1475 const int netfid, const unsigned int count,
1476 const __u64 offset, unsigned int *nbytes, const char *buf,
1477 const char __user *ubuf, const int long_op)
1478{
1479 int rc = -EACCES;
1480 WRITE_REQ *pSMB = NULL;
1481 WRITE_RSP *pSMBr = NULL;
1482 int bytes_returned, wct;
1483 __u32 bytes_sent;
1484 __u16 byte_count;
1485
1486 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1487 if (tcon->ses == NULL)
1488 return -ECONNABORTED;
1489
1490 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1491 wct = 14;
1492 else
1493 wct = 12;
1494
1495 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1496 (void **) &pSMBr);
1497 if (rc)
1498 return rc;
1499 /* tcon and ses pointer are checked in smb_init */
1500 if (tcon->ses->server == NULL)
1501 return -ECONNABORTED;
1502
1503 pSMB->AndXCommand = 0xFF; /* none */
1504 pSMB->Fid = netfid;
1505 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1506 if (wct == 14)
1507 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1508 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1509 return -EIO;
1510
1511 pSMB->Reserved = 0xFFFFFFFF;
1512 pSMB->WriteMode = 0;
1513 pSMB->Remaining = 0;
1514
1515 /* Can increase buffer size if buffer is big enough in some cases ie we
1516 can send more if LARGE_WRITE_X capability returned by the server and if
1517 our buffer is big enough or if we convert to iovecs on socket writes
1518 and eliminate the copy to the CIFS buffer */
1519 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1520 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1521 } else {
1522 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1523 & ~0xFF;
1524 }
1525
1526 if (bytes_sent > count)
1527 bytes_sent = count;
1528 pSMB->DataOffset =
1529 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1530 if (buf)
1531 memcpy(pSMB->Data, buf, bytes_sent);
1532 else if (ubuf) {
1533 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1534 cifs_buf_release(pSMB);
1535 return -EFAULT;
1536 }
1537 } else if (count != 0) {
1538 /* No buffer */
1539 cifs_buf_release(pSMB);
1540 return -EINVAL;
1541 } /* else setting file size with write of zero bytes */
1542 if (wct == 14)
1543 byte_count = bytes_sent + 1; /* pad */
1544 else /* wct == 12 */ {
1545 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
1546 }
1547 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1548 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1549 pSMB->hdr.smb_buf_length += byte_count;
1550
1551 if (wct == 14)
1552 pSMB->ByteCount = cpu_to_le16(byte_count);
1553 else { /* old style write has byte count 4 bytes earlier
1554 so 4 bytes pad */
1555 struct smb_com_writex_req *pSMBW =
1556 (struct smb_com_writex_req *)pSMB;
1557 pSMBW->ByteCount = cpu_to_le16(byte_count);
1558 }
1559
1560 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1561 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1562 cifs_stats_inc(&tcon->num_writes);
1563 if (rc) {
1564 cFYI(1, ("Send error in write = %d", rc));
1565 *nbytes = 0;
1566 } else {
1567 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1568 *nbytes = (*nbytes) << 16;
1569 *nbytes += le16_to_cpu(pSMBr->Count);
1570 }
1571
1572 cifs_buf_release(pSMB);
1573
1574 /* Note: On -EAGAIN error only caller can retry on handle based calls
1575 since file handle passed in no longer valid */
1576
1577 return rc;
1578}
1579
1580int
1581CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1582 const int netfid, const unsigned int count,
1583 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1584 int n_vec, const int long_op)
1585{
1586 int rc = -EACCES;
1587 WRITE_REQ *pSMB = NULL;
1588 int wct;
1589 int smb_hdr_len;
1590 int resp_buf_type = 0;
1591
1592 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
1593
1594 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1595 wct = 14;
1596 else
1597 wct = 12;
1598 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1599 if (rc)
1600 return rc;
1601 /* tcon and ses pointer are checked in smb_init */
1602 if (tcon->ses->server == NULL)
1603 return -ECONNABORTED;
1604
1605 pSMB->AndXCommand = 0xFF; /* none */
1606 pSMB->Fid = netfid;
1607 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1608 if (wct == 14)
1609 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1610 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
1611 return -EIO;
1612 pSMB->Reserved = 0xFFFFFFFF;
1613 pSMB->WriteMode = 0;
1614 pSMB->Remaining = 0;
1615
1616 pSMB->DataOffset =
1617 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1618
1619 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1620 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
1621 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1622 if (wct == 14)
1623 pSMB->hdr.smb_buf_length += count+1;
1624 else /* wct == 12 */
1625 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1626 if (wct == 14)
1627 pSMB->ByteCount = cpu_to_le16(count + 1);
1628 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1629 struct smb_com_writex_req *pSMBW =
1630 (struct smb_com_writex_req *)pSMB;
1631 pSMBW->ByteCount = cpu_to_le16(count + 5);
1632 }
1633 iov[0].iov_base = pSMB;
1634 if (wct == 14)
1635 iov[0].iov_len = smb_hdr_len + 4;
1636 else /* wct == 12 pad bigger by four bytes */
1637 iov[0].iov_len = smb_hdr_len + 8;
1638
1639
1640 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
1641 long_op);
1642 cifs_stats_inc(&tcon->num_writes);
1643 if (rc) {
1644 cFYI(1, ("Send error Write2 = %d", rc));
1645 *nbytes = 0;
1646 } else if (resp_buf_type == 0) {
1647 /* presumably this can not happen, but best to be safe */
1648 rc = -EIO;
1649 *nbytes = 0;
1650 } else {
1651 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
1652 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1653 *nbytes = (*nbytes) << 16;
1654 *nbytes += le16_to_cpu(pSMBr->Count);
1655 }
1656
1657/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
1658 if (resp_buf_type == CIFS_SMALL_BUFFER)
1659 cifs_small_buf_release(iov[0].iov_base);
1660 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1661 cifs_buf_release(iov[0].iov_base);
1662
1663 /* Note: On -EAGAIN error only caller can retry on handle based calls
1664 since file handle passed in no longer valid */
1665
1666 return rc;
1667}
1668
1669
1670int
1671CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1672 const __u16 smb_file_id, const __u64 len,
1673 const __u64 offset, const __u32 numUnlock,
1674 const __u32 numLock, const __u8 lockType, const int waitFlag)
1675{
1676 int rc = 0;
1677 LOCK_REQ *pSMB = NULL;
1678 LOCK_RSP *pSMBr = NULL;
1679 int bytes_returned;
1680 int timeout = 0;
1681 __u16 count;
1682
1683 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
1684 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1685
1686 if (rc)
1687 return rc;
1688
1689 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1690
1691 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1692 timeout = -1; /* no response expected */
1693 pSMB->Timeout = 0;
1694 } else if (waitFlag == TRUE) {
1695 timeout = 3; /* blocking operation, no timeout */
1696 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1697 } else {
1698 pSMB->Timeout = 0;
1699 }
1700
1701 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1702 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1703 pSMB->LockType = lockType;
1704 pSMB->AndXCommand = 0xFF; /* none */
1705 pSMB->Fid = smb_file_id; /* netfid stays le */
1706
1707 if ((numLock != 0) || (numUnlock != 0)) {
1708 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1709 /* BB where to store pid high? */
1710 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1711 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1712 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1713 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1714 count = sizeof(LOCKING_ANDX_RANGE);
1715 } else {
1716 /* oplock break */
1717 count = 0;
1718 }
1719 pSMB->hdr.smb_buf_length += count;
1720 pSMB->ByteCount = cpu_to_le16(count);
1721
1722 if (waitFlag) {
1723 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1724 (struct smb_hdr *) pSMBr, &bytes_returned);
1725 } else {
1726 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1727 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1728 }
1729 cifs_stats_inc(&tcon->num_locks);
1730 if (rc) {
1731 cFYI(1, ("Send error in Lock = %d", rc));
1732 }
1733 cifs_small_buf_release(pSMB);
1734
1735 /* Note: On -EAGAIN error only caller can retry on handle based calls
1736 since file handle passed in no longer valid */
1737 return rc;
1738}
1739
1740int
1741CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1742 const __u16 smb_file_id, const int get_flag, const __u64 len,
1743 struct file_lock *pLockData, const __u16 lock_type,
1744 const int waitFlag)
1745{
1746 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1747 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1748 struct cifs_posix_lock *parm_data;
1749 int rc = 0;
1750 int timeout = 0;
1751 int bytes_returned = 0;
1752 __u16 params, param_offset, offset, byte_count, count;
1753
1754 cFYI(1, ("Posix Lock"));
1755
1756 if (pLockData == NULL)
1757 return EINVAL;
1758
1759 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1760
1761 if (rc)
1762 return rc;
1763
1764 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1765
1766 params = 6;
1767 pSMB->MaxSetupCount = 0;
1768 pSMB->Reserved = 0;
1769 pSMB->Flags = 0;
1770 pSMB->Reserved2 = 0;
1771 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1772 offset = param_offset + params;
1773
1774 count = sizeof(struct cifs_posix_lock);
1775 pSMB->MaxParameterCount = cpu_to_le16(2);
1776 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1777 pSMB->SetupCount = 1;
1778 pSMB->Reserved3 = 0;
1779 if (get_flag)
1780 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1781 else
1782 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1783 byte_count = 3 /* pad */ + params + count;
1784 pSMB->DataCount = cpu_to_le16(count);
1785 pSMB->ParameterCount = cpu_to_le16(params);
1786 pSMB->TotalDataCount = pSMB->DataCount;
1787 pSMB->TotalParameterCount = pSMB->ParameterCount;
1788 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1789 parm_data = (struct cifs_posix_lock *)
1790 (((char *) &pSMB->hdr.Protocol) + offset);
1791
1792 parm_data->lock_type = cpu_to_le16(lock_type);
1793 if (waitFlag) {
1794 timeout = 3; /* blocking operation, no timeout */
1795 parm_data->lock_flags = cpu_to_le16(1);
1796 pSMB->Timeout = cpu_to_le32(-1);
1797 } else
1798 pSMB->Timeout = 0;
1799
1800 parm_data->pid = cpu_to_le32(current->tgid);
1801 parm_data->start = cpu_to_le64(pLockData->fl_start);
1802 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
1803
1804 pSMB->DataOffset = cpu_to_le16(offset);
1805 pSMB->Fid = smb_file_id;
1806 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1807 pSMB->Reserved4 = 0;
1808 pSMB->hdr.smb_buf_length += byte_count;
1809 pSMB->ByteCount = cpu_to_le16(byte_count);
1810 if (waitFlag) {
1811 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1812 (struct smb_hdr *) pSMBr, &bytes_returned);
1813 } else {
1814 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1815 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1816 }
1817
1818 if (rc) {
1819 cFYI(1, ("Send error in Posix Lock = %d", rc));
1820 } else if (get_flag) {
1821 /* lock structure can be returned on get */
1822 __u16 data_offset;
1823 __u16 data_count;
1824 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1825
1826 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1827 rc = -EIO; /* bad smb */
1828 goto plk_err_exit;
1829 }
1830 if (pLockData == NULL) {
1831 rc = -EINVAL;
1832 goto plk_err_exit;
1833 }
1834 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1835 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1836 if (data_count < sizeof(struct cifs_posix_lock)) {
1837 rc = -EIO;
1838 goto plk_err_exit;
1839 }
1840 parm_data = (struct cifs_posix_lock *)
1841 ((char *)&pSMBr->hdr.Protocol + data_offset);
1842 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1843 pLockData->fl_type = F_UNLCK;
1844 }
1845
1846plk_err_exit:
1847 if (pSMB)
1848 cifs_small_buf_release(pSMB);
1849
1850 /* Note: On -EAGAIN error only caller can retry on handle based calls
1851 since file handle passed in no longer valid */
1852
1853 return rc;
1854}
1855
1856
1857int
1858CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1859{
1860 int rc = 0;
1861 CLOSE_REQ *pSMB = NULL;
1862 CLOSE_RSP *pSMBr = NULL;
1863 int bytes_returned;
1864 cFYI(1, ("In CIFSSMBClose"));
1865
1866/* do not retry on dead session on close */
1867 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1868 if (rc == -EAGAIN)
1869 return 0;
1870 if (rc)
1871 return rc;
1872
1873 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1874
1875 pSMB->FileID = (__u16) smb_file_id;
1876 pSMB->LastWriteTime = 0xFFFFFFFF;
1877 pSMB->ByteCount = 0;
1878 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1879 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1880 cifs_stats_inc(&tcon->num_closes);
1881 if (rc) {
1882 if (rc != -EINTR) {
1883 /* EINTR is expected when user ctl-c to kill app */
1884 cERROR(1, ("Send error in Close = %d", rc));
1885 }
1886 }
1887
1888 cifs_small_buf_release(pSMB);
1889
1890 /* Since session is dead, file will be closed on server already */
1891 if (rc == -EAGAIN)
1892 rc = 0;
1893
1894 return rc;
1895}
1896
1897int
1898CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1899 const char *fromName, const char *toName,
1900 const struct nls_table *nls_codepage, int remap)
1901{
1902 int rc = 0;
1903 RENAME_REQ *pSMB = NULL;
1904 RENAME_RSP *pSMBr = NULL;
1905 int bytes_returned;
1906 int name_len, name_len2;
1907 __u16 count;
1908
1909 cFYI(1, ("In CIFSSMBRename"));
1910renameRetry:
1911 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1912 (void **) &pSMBr);
1913 if (rc)
1914 return rc;
1915
1916 pSMB->BufferFormat = 0x04;
1917 pSMB->SearchAttributes =
1918 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1919 ATTR_DIRECTORY);
1920
1921 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1922 name_len =
1923 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1924 PATH_MAX, nls_codepage, remap);
1925 name_len++; /* trailing null */
1926 name_len *= 2;
1927 pSMB->OldFileName[name_len] = 0x04; /* pad */
1928 /* protocol requires ASCII signature byte on Unicode string */
1929 pSMB->OldFileName[name_len + 1] = 0x00;
1930 name_len2 =
1931 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1932 toName, PATH_MAX, nls_codepage, remap);
1933 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1934 name_len2 *= 2; /* convert to bytes */
1935 } else { /* BB improve the check for buffer overruns BB */
1936 name_len = strnlen(fromName, PATH_MAX);
1937 name_len++; /* trailing null */
1938 strncpy(pSMB->OldFileName, fromName, name_len);
1939 name_len2 = strnlen(toName, PATH_MAX);
1940 name_len2++; /* trailing null */
1941 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1942 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1943 name_len2++; /* trailing null */
1944 name_len2++; /* signature byte */
1945 }
1946
1947 count = 1 /* 1st signature byte */ + name_len + name_len2;
1948 pSMB->hdr.smb_buf_length += count;
1949 pSMB->ByteCount = cpu_to_le16(count);
1950
1951 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1952 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1953 cifs_stats_inc(&tcon->num_renames);
1954 if (rc) {
1955 cFYI(1, ("Send error in rename = %d", rc));
1956 }
1957
1958 cifs_buf_release(pSMB);
1959
1960 if (rc == -EAGAIN)
1961 goto renameRetry;
1962
1963 return rc;
1964}
1965
1966int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1967 int netfid, char *target_name,
1968 const struct nls_table *nls_codepage, int remap)
1969{
1970 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1971 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1972 struct set_file_rename *rename_info;
1973 char *data_offset;
1974 char dummy_string[30];
1975 int rc = 0;
1976 int bytes_returned = 0;
1977 int len_of_str;
1978 __u16 params, param_offset, offset, count, byte_count;
1979
1980 cFYI(1, ("Rename to File by handle"));
1981 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1982 (void **) &pSMBr);
1983 if (rc)
1984 return rc;
1985
1986 params = 6;
1987 pSMB->MaxSetupCount = 0;
1988 pSMB->Reserved = 0;
1989 pSMB->Flags = 0;
1990 pSMB->Timeout = 0;
1991 pSMB->Reserved2 = 0;
1992 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1993 offset = param_offset + params;
1994
1995 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1996 rename_info = (struct set_file_rename *) data_offset;
1997 pSMB->MaxParameterCount = cpu_to_le16(2);
1998 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1999 pSMB->SetupCount = 1;
2000 pSMB->Reserved3 = 0;
2001 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2002 byte_count = 3 /* pad */ + params;
2003 pSMB->ParameterCount = cpu_to_le16(params);
2004 pSMB->TotalParameterCount = pSMB->ParameterCount;
2005 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2006 pSMB->DataOffset = cpu_to_le16(offset);
2007 /* construct random name ".cifs_tmp<inodenum><mid>" */
2008 rename_info->overwrite = cpu_to_le32(1);
2009 rename_info->root_fid = 0;
2010 /* unicode only call */
2011 if (target_name == NULL) {
2012 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2013 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2014 dummy_string, 24, nls_codepage, remap);
2015 } else {
2016 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
2017 target_name, PATH_MAX, nls_codepage,
2018 remap);
2019 }
2020 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2021 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2022 byte_count += count;
2023 pSMB->DataCount = cpu_to_le16(count);
2024 pSMB->TotalDataCount = pSMB->DataCount;
2025 pSMB->Fid = netfid;
2026 pSMB->InformationLevel =
2027 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2028 pSMB->Reserved4 = 0;
2029 pSMB->hdr.smb_buf_length += byte_count;
2030 pSMB->ByteCount = cpu_to_le16(byte_count);
2031 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2032 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2033 cifs_stats_inc(&pTcon->num_t2renames);
2034 if (rc) {
2035 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
2036 }
2037
2038 cifs_buf_release(pSMB);
2039
2040 /* Note: On -EAGAIN error only caller can retry on handle based calls
2041 since file handle passed in no longer valid */
2042
2043 return rc;
2044}
2045
2046int
2047CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2048 const __u16 target_tid, const char *toName, const int flags,
2049 const struct nls_table *nls_codepage, int remap)
2050{
2051 int rc = 0;
2052 COPY_REQ *pSMB = NULL;
2053 COPY_RSP *pSMBr = NULL;
2054 int bytes_returned;
2055 int name_len, name_len2;
2056 __u16 count;
2057
2058 cFYI(1, ("In CIFSSMBCopy"));
2059copyRetry:
2060 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2061 (void **) &pSMBr);
2062 if (rc)
2063 return rc;
2064
2065 pSMB->BufferFormat = 0x04;
2066 pSMB->Tid2 = target_tid;
2067
2068 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2069
2070 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2071 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
2072 fromName, PATH_MAX, nls_codepage,
2073 remap);
2074 name_len++; /* trailing null */
2075 name_len *= 2;
2076 pSMB->OldFileName[name_len] = 0x04; /* pad */
2077 /* protocol requires ASCII signature byte on Unicode string */
2078 pSMB->OldFileName[name_len + 1] = 0x00;
2079 name_len2 =
2080 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2081 toName, PATH_MAX, nls_codepage, remap);
2082 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2083 name_len2 *= 2; /* convert to bytes */
2084 } else { /* BB improve the check for buffer overruns BB */
2085 name_len = strnlen(fromName, PATH_MAX);
2086 name_len++; /* trailing null */
2087 strncpy(pSMB->OldFileName, fromName, name_len);
2088 name_len2 = strnlen(toName, PATH_MAX);
2089 name_len2++; /* trailing null */
2090 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2091 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2092 name_len2++; /* trailing null */
2093 name_len2++; /* signature byte */
2094 }
2095
2096 count = 1 /* 1st signature byte */ + name_len + name_len2;
2097 pSMB->hdr.smb_buf_length += count;
2098 pSMB->ByteCount = cpu_to_le16(count);
2099
2100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2101 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2102 if (rc) {
2103 cFYI(1, ("Send error in copy = %d with %d files copied",
2104 rc, le16_to_cpu(pSMBr->CopyCount)));
2105 }
2106 if (pSMB)
2107 cifs_buf_release(pSMB);
2108
2109 if (rc == -EAGAIN)
2110 goto copyRetry;
2111
2112 return rc;
2113}
2114
2115int
2116CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2117 const char *fromName, const char *toName,
2118 const struct nls_table *nls_codepage)
2119{
2120 TRANSACTION2_SPI_REQ *pSMB = NULL;
2121 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2122 char *data_offset;
2123 int name_len;
2124 int name_len_target;
2125 int rc = 0;
2126 int bytes_returned = 0;
2127 __u16 params, param_offset, offset, byte_count;
2128
2129 cFYI(1, ("In Symlink Unix style"));
2130createSymLinkRetry:
2131 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2132 (void **) &pSMBr);
2133 if (rc)
2134 return rc;
2135
2136 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2137 name_len =
2138 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
2139 /* find define for this maxpathcomponent */
2140 , nls_codepage);
2141 name_len++; /* trailing null */
2142 name_len *= 2;
2143
2144 } else { /* BB improve the check for buffer overruns BB */
2145 name_len = strnlen(fromName, PATH_MAX);
2146 name_len++; /* trailing null */
2147 strncpy(pSMB->FileName, fromName, name_len);
2148 }
2149 params = 6 + name_len;
2150 pSMB->MaxSetupCount = 0;
2151 pSMB->Reserved = 0;
2152 pSMB->Flags = 0;
2153 pSMB->Timeout = 0;
2154 pSMB->Reserved2 = 0;
2155 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2156 InformationLevel) - 4;
2157 offset = param_offset + params;
2158
2159 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2160 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2161 name_len_target =
2162 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
2163 /* find define for this maxpathcomponent */
2164 , nls_codepage);
2165 name_len_target++; /* trailing null */
2166 name_len_target *= 2;
2167 } else { /* BB improve the check for buffer overruns BB */
2168 name_len_target = strnlen(toName, PATH_MAX);
2169 name_len_target++; /* trailing null */
2170 strncpy(data_offset, toName, name_len_target);
2171 }
2172
2173 pSMB->MaxParameterCount = cpu_to_le16(2);
2174 /* BB find exact max on data count below from sess */
2175 pSMB->MaxDataCount = cpu_to_le16(1000);
2176 pSMB->SetupCount = 1;
2177 pSMB->Reserved3 = 0;
2178 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2179 byte_count = 3 /* pad */ + params + name_len_target;
2180 pSMB->DataCount = cpu_to_le16(name_len_target);
2181 pSMB->ParameterCount = cpu_to_le16(params);
2182 pSMB->TotalDataCount = pSMB->DataCount;
2183 pSMB->TotalParameterCount = pSMB->ParameterCount;
2184 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2185 pSMB->DataOffset = cpu_to_le16(offset);
2186 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2187 pSMB->Reserved4 = 0;
2188 pSMB->hdr.smb_buf_length += byte_count;
2189 pSMB->ByteCount = cpu_to_le16(byte_count);
2190 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2191 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2192 cifs_stats_inc(&tcon->num_symlinks);
2193 if (rc) {
2194 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
2195 }
2196
2197 if (pSMB)
2198 cifs_buf_release(pSMB);
2199
2200 if (rc == -EAGAIN)
2201 goto createSymLinkRetry;
2202
2203 return rc;
2204}
2205
2206int
2207CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2208 const char *fromName, const char *toName,
2209 const struct nls_table *nls_codepage, int remap)
2210{
2211 TRANSACTION2_SPI_REQ *pSMB = NULL;
2212 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2213 char *data_offset;
2214 int name_len;
2215 int name_len_target;
2216 int rc = 0;
2217 int bytes_returned = 0;
2218 __u16 params, param_offset, offset, byte_count;
2219
2220 cFYI(1, ("In Create Hard link Unix style"));
2221createHardLinkRetry:
2222 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2223 (void **) &pSMBr);
2224 if (rc)
2225 return rc;
2226
2227 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2228 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
2229 PATH_MAX, nls_codepage, remap);
2230 name_len++; /* trailing null */
2231 name_len *= 2;
2232
2233 } else { /* BB improve the check for buffer overruns BB */
2234 name_len = strnlen(toName, PATH_MAX);
2235 name_len++; /* trailing null */
2236 strncpy(pSMB->FileName, toName, name_len);
2237 }
2238 params = 6 + name_len;
2239 pSMB->MaxSetupCount = 0;
2240 pSMB->Reserved = 0;
2241 pSMB->Flags = 0;
2242 pSMB->Timeout = 0;
2243 pSMB->Reserved2 = 0;
2244 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2245 InformationLevel) - 4;
2246 offset = param_offset + params;
2247
2248 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2249 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2250 name_len_target =
2251 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
2252 nls_codepage, remap);
2253 name_len_target++; /* trailing null */
2254 name_len_target *= 2;
2255 } else { /* BB improve the check for buffer overruns BB */
2256 name_len_target = strnlen(fromName, PATH_MAX);
2257 name_len_target++; /* trailing null */
2258 strncpy(data_offset, fromName, name_len_target);
2259 }
2260
2261 pSMB->MaxParameterCount = cpu_to_le16(2);
2262 /* BB find exact max on data count below from sess*/
2263 pSMB->MaxDataCount = cpu_to_le16(1000);
2264 pSMB->SetupCount = 1;
2265 pSMB->Reserved3 = 0;
2266 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2267 byte_count = 3 /* pad */ + params + name_len_target;
2268 pSMB->ParameterCount = cpu_to_le16(params);
2269 pSMB->TotalParameterCount = pSMB->ParameterCount;
2270 pSMB->DataCount = cpu_to_le16(name_len_target);
2271 pSMB->TotalDataCount = pSMB->DataCount;
2272 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2273 pSMB->DataOffset = cpu_to_le16(offset);
2274 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2275 pSMB->Reserved4 = 0;
2276 pSMB->hdr.smb_buf_length += byte_count;
2277 pSMB->ByteCount = cpu_to_le16(byte_count);
2278 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2279 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2280 cifs_stats_inc(&tcon->num_hardlinks);
2281 if (rc) {
2282 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2283 }
2284
2285 cifs_buf_release(pSMB);
2286 if (rc == -EAGAIN)
2287 goto createHardLinkRetry;
2288
2289 return rc;
2290}
2291
2292int
2293CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2294 const char *fromName, const char *toName,
2295 const struct nls_table *nls_codepage, int remap)
2296{
2297 int rc = 0;
2298 NT_RENAME_REQ *pSMB = NULL;
2299 RENAME_RSP *pSMBr = NULL;
2300 int bytes_returned;
2301 int name_len, name_len2;
2302 __u16 count;
2303
2304 cFYI(1, ("In CIFSCreateHardLink"));
2305winCreateHardLinkRetry:
2306
2307 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2308 (void **) &pSMBr);
2309 if (rc)
2310 return rc;
2311
2312 pSMB->SearchAttributes =
2313 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2314 ATTR_DIRECTORY);
2315 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2316 pSMB->ClusterCount = 0;
2317
2318 pSMB->BufferFormat = 0x04;
2319
2320 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2321 name_len =
2322 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
2323 PATH_MAX, nls_codepage, remap);
2324 name_len++; /* trailing null */
2325 name_len *= 2;
2326 pSMB->OldFileName[name_len] = 0; /* pad */
2327 pSMB->OldFileName[name_len + 1] = 0x04;
2328 name_len2 =
2329 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
2330 toName, PATH_MAX, nls_codepage, remap);
2331 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2332 name_len2 *= 2; /* convert to bytes */
2333 } else { /* BB improve the check for buffer overruns BB */
2334 name_len = strnlen(fromName, PATH_MAX);
2335 name_len++; /* trailing null */
2336 strncpy(pSMB->OldFileName, fromName, name_len);
2337 name_len2 = strnlen(toName, PATH_MAX);
2338 name_len2++; /* trailing null */
2339 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2340 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2341 name_len2++; /* trailing null */
2342 name_len2++; /* signature byte */
2343 }
2344
2345 count = 1 /* string type byte */ + name_len + name_len2;
2346 pSMB->hdr.smb_buf_length += count;
2347 pSMB->ByteCount = cpu_to_le16(count);
2348
2349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2351 cifs_stats_inc(&tcon->num_hardlinks);
2352 if (rc) {
2353 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2354 }
2355 cifs_buf_release(pSMB);
2356 if (rc == -EAGAIN)
2357 goto winCreateHardLinkRetry;
2358
2359 return rc;
2360}
2361
2362int
2363CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2364 const unsigned char *searchName,
2365 char *symlinkinfo, const int buflen,
2366 const struct nls_table *nls_codepage)
2367{
2368/* SMB_QUERY_FILE_UNIX_LINK */
2369 TRANSACTION2_QPI_REQ *pSMB = NULL;
2370 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2371 int rc = 0;
2372 int bytes_returned;
2373 int name_len;
2374 __u16 params, byte_count;
2375
2376 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2377
2378querySymLinkRetry:
2379 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2380 (void **) &pSMBr);
2381 if (rc)
2382 return rc;
2383
2384 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2385 name_len =
2386 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2387 PATH_MAX, nls_codepage);
2388 name_len++; /* trailing null */
2389 name_len *= 2;
2390 } else { /* BB improve the check for buffer overruns BB */
2391 name_len = strnlen(searchName, PATH_MAX);
2392 name_len++; /* trailing null */
2393 strncpy(pSMB->FileName, searchName, name_len);
2394 }
2395
2396 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2397 pSMB->TotalDataCount = 0;
2398 pSMB->MaxParameterCount = cpu_to_le16(2);
2399 /* BB find exact max data count below from sess structure BB */
2400 pSMB->MaxDataCount = cpu_to_le16(4000);
2401 pSMB->MaxSetupCount = 0;
2402 pSMB->Reserved = 0;
2403 pSMB->Flags = 0;
2404 pSMB->Timeout = 0;
2405 pSMB->Reserved2 = 0;
2406 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2407 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
2408 pSMB->DataCount = 0;
2409 pSMB->DataOffset = 0;
2410 pSMB->SetupCount = 1;
2411 pSMB->Reserved3 = 0;
2412 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2413 byte_count = params + 1 /* pad */ ;
2414 pSMB->TotalParameterCount = cpu_to_le16(params);
2415 pSMB->ParameterCount = pSMB->TotalParameterCount;
2416 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2417 pSMB->Reserved4 = 0;
2418 pSMB->hdr.smb_buf_length += byte_count;
2419 pSMB->ByteCount = cpu_to_le16(byte_count);
2420
2421 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2422 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2423 if (rc) {
2424 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2425 } else {
2426 /* decode response */
2427
2428 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2429 if (rc || (pSMBr->ByteCount < 2))
2430 /* BB also check enough total bytes returned */
2431 rc = -EIO; /* bad smb */
2432 else {
2433 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2434 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2435
2436 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2437 name_len = UniStrnlen((wchar_t *) ((char *)
2438 &pSMBr->hdr.Protocol + data_offset),
2439 min_t(const int, buflen, count) / 2);
2440 /* BB FIXME investigate remapping reserved chars here */
2441 cifs_strfromUCS_le(symlinkinfo,
2442 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2443 + data_offset),
2444 name_len, nls_codepage);
2445 } else {
2446 strncpy(symlinkinfo,
2447 (char *) &pSMBr->hdr.Protocol +
2448 data_offset,
2449 min_t(const int, buflen, count));
2450 }
2451 symlinkinfo[buflen] = 0;
2452 /* just in case so calling code does not go off the end of buffer */
2453 }
2454 }
2455 cifs_buf_release(pSMB);
2456 if (rc == -EAGAIN)
2457 goto querySymLinkRetry;
2458 return rc;
2459}
2460
2461/* Initialize NT TRANSACT SMB into small smb request buffer.
2462 This assumes that all NT TRANSACTS that we init here have
2463 total parm and data under about 400 bytes (to fit in small cifs
2464 buffer size), which is the case so far, it easily fits. NB:
2465 Setup words themselves and ByteCount
2466 MaxSetupCount (size of returned setup area) and
2467 MaxParameterCount (returned parms size) must be set by caller */
2468static int
2469smb_init_ntransact(const __u16 sub_command, const int setup_count,
2470 const int parm_len, struct cifsTconInfo *tcon,
2471 void **ret_buf)
2472{
2473 int rc;
2474 __u32 temp_offset;
2475 struct smb_com_ntransact_req *pSMB;
2476
2477 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2478 (void **)&pSMB);
2479 if (rc)
2480 return rc;
2481 *ret_buf = (void *)pSMB;
2482 pSMB->Reserved = 0;
2483 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2484 pSMB->TotalDataCount = 0;
2485 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2486 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2487 pSMB->ParameterCount = pSMB->TotalParameterCount;
2488 pSMB->DataCount = pSMB->TotalDataCount;
2489 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2490 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2491 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2492 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2493 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2494 pSMB->SubCommand = cpu_to_le16(sub_command);
2495 return 0;
2496}
2497
2498static int
2499validate_ntransact(char *buf, char **ppparm, char **ppdata,
2500 int *pdatalen, int *pparmlen)
2501{
2502 char *end_of_smb;
2503 __u32 data_count, data_offset, parm_count, parm_offset;
2504 struct smb_com_ntransact_rsp *pSMBr;
2505
2506 if (buf == NULL)
2507 return -EINVAL;
2508
2509 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2510
2511 /* ByteCount was converted from little endian in SendReceive */
2512 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2513 (char *)&pSMBr->ByteCount;
2514
2515 data_offset = le32_to_cpu(pSMBr->DataOffset);
2516 data_count = le32_to_cpu(pSMBr->DataCount);
2517 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2518 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2519
2520 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2521 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2522
2523 /* should we also check that parm and data areas do not overlap? */
2524 if (*ppparm > end_of_smb) {
2525 cFYI(1, ("parms start after end of smb"));
2526 return -EINVAL;
2527 } else if (parm_count + *ppparm > end_of_smb) {
2528 cFYI(1, ("parm end after end of smb"));
2529 return -EINVAL;
2530 } else if (*ppdata > end_of_smb) {
2531 cFYI(1, ("data starts after end of smb"));
2532 return -EINVAL;
2533 } else if (data_count + *ppdata > end_of_smb) {
2534 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2535 *ppdata, data_count, (data_count + *ppdata),
2536 end_of_smb, pSMBr));
2537 return -EINVAL;
2538 } else if (parm_count + data_count > pSMBr->ByteCount) {
2539 cFYI(1, ("parm count and data count larger than SMB"));
2540 return -EINVAL;
2541 }
2542 return 0;
2543}
2544
2545int
2546CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2547 const unsigned char *searchName,
2548 char *symlinkinfo, const int buflen, __u16 fid,
2549 const struct nls_table *nls_codepage)
2550{
2551 int rc = 0;
2552 int bytes_returned;
2553 int name_len;
2554 struct smb_com_transaction_ioctl_req *pSMB;
2555 struct smb_com_transaction_ioctl_rsp *pSMBr;
2556
2557 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2558 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2559 (void **) &pSMBr);
2560 if (rc)
2561 return rc;
2562
2563 pSMB->TotalParameterCount = 0 ;
2564 pSMB->TotalDataCount = 0;
2565 pSMB->MaxParameterCount = cpu_to_le32(2);
2566 /* BB find exact data count max from sess structure BB */
2567 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2568 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2569 pSMB->MaxSetupCount = 4;
2570 pSMB->Reserved = 0;
2571 pSMB->ParameterOffset = 0;
2572 pSMB->DataCount = 0;
2573 pSMB->DataOffset = 0;
2574 pSMB->SetupCount = 4;
2575 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2576 pSMB->ParameterCount = pSMB->TotalParameterCount;
2577 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2578 pSMB->IsFsctl = 1; /* FSCTL */
2579 pSMB->IsRootFlag = 0;
2580 pSMB->Fid = fid; /* file handle always le */
2581 pSMB->ByteCount = 0;
2582
2583 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2584 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2585 if (rc) {
2586 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2587 } else { /* decode response */
2588 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2589 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2590 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2591 /* BB also check enough total bytes returned */
2592 rc = -EIO; /* bad smb */
2593 else {
2594 if (data_count && (data_count < 2048)) {
2595 char *end_of_smb = 2 /* sizeof byte count */ +
2596 pSMBr->ByteCount +
2597 (char *)&pSMBr->ByteCount;
2598
2599 struct reparse_data *reparse_buf =
2600 (struct reparse_data *)
2601 ((char *)&pSMBr->hdr.Protocol
2602 + data_offset);
2603 if ((char *)reparse_buf >= end_of_smb) {
2604 rc = -EIO;
2605 goto qreparse_out;
2606 }
2607 if ((reparse_buf->LinkNamesBuf +
2608 reparse_buf->TargetNameOffset +
2609 reparse_buf->TargetNameLen) >
2610 end_of_smb) {
2611 cFYI(1,("reparse buf extended beyond SMB"));
2612 rc = -EIO;
2613 goto qreparse_out;
2614 }
2615
2616 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2617 name_len = UniStrnlen((wchar_t *)
2618 (reparse_buf->LinkNamesBuf +
2619 reparse_buf->TargetNameOffset),
2620 min(buflen/2,
2621 reparse_buf->TargetNameLen / 2));
2622 cifs_strfromUCS_le(symlinkinfo,
2623 (__le16 *) (reparse_buf->LinkNamesBuf +
2624 reparse_buf->TargetNameOffset),
2625 name_len, nls_codepage);
2626 } else { /* ASCII names */
2627 strncpy(symlinkinfo,
2628 reparse_buf->LinkNamesBuf +
2629 reparse_buf->TargetNameOffset,
2630 min_t(const int, buflen,
2631 reparse_buf->TargetNameLen));
2632 }
2633 } else {
2634 rc = -EIO;
2635 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2636 }
2637 symlinkinfo[buflen] = 0; /* just in case so the caller
2638 does not go off the end of the buffer */
2639 cFYI(1, ("readlink result - %s", symlinkinfo));
2640 }
2641 }
2642qreparse_out:
2643 cifs_buf_release(pSMB);
2644
2645 /* Note: On -EAGAIN error only caller can retry on handle based calls
2646 since file handle passed in no longer valid */
2647
2648 return rc;
2649}
2650
2651#ifdef CONFIG_CIFS_POSIX
2652
2653/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2654static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2655 struct cifs_posix_ace *cifs_ace)
2656{
2657 /* u8 cifs fields do not need le conversion */
2658 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2659 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2660 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2661 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2662
2663 return;
2664}
2665
2666/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2667static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2668 const int acl_type, const int size_of_data_area)
2669{
2670 int size = 0;
2671 int i;
2672 __u16 count;
2673 struct cifs_posix_ace *pACE;
2674 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2675 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
2676
2677 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2678 return -EOPNOTSUPP;
2679
2680 if (acl_type & ACL_TYPE_ACCESS) {
2681 count = le16_to_cpu(cifs_acl->access_entry_count);
2682 pACE = &cifs_acl->ace_array[0];
2683 size = sizeof(struct cifs_posix_acl);
2684 size += sizeof(struct cifs_posix_ace) * count;
2685 /* check if we would go beyond end of SMB */
2686 if (size_of_data_area < size) {
2687 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2688 size_of_data_area, size));
2689 return -EINVAL;
2690 }
2691 } else if (acl_type & ACL_TYPE_DEFAULT) {
2692 count = le16_to_cpu(cifs_acl->access_entry_count);
2693 size = sizeof(struct cifs_posix_acl);
2694 size += sizeof(struct cifs_posix_ace) * count;
2695/* skip past access ACEs to get to default ACEs */
2696 pACE = &cifs_acl->ace_array[count];
2697 count = le16_to_cpu(cifs_acl->default_entry_count);
2698 size += sizeof(struct cifs_posix_ace) * count;
2699 /* check if we would go beyond end of SMB */
2700 if (size_of_data_area < size)
2701 return -EINVAL;
2702 } else {
2703 /* illegal type */
2704 return -EINVAL;
2705 }
2706
2707 size = posix_acl_xattr_size(count);
2708 if ((buflen == 0) || (local_acl == NULL)) {
2709 /* used to query ACL EA size */
2710 } else if (size > buflen) {
2711 return -ERANGE;
2712 } else /* buffer big enough */ {
2713 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2714 for (i = 0; i < count ; i++) {
2715 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2716 pACE++;
2717 }
2718 }
2719 return size;
2720}
2721
2722static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2723 const posix_acl_xattr_entry *local_ace)
2724{
2725 __u16 rc = 0; /* 0 = ACL converted ok */
2726
2727 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2728 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
2729 /* BB is there a better way to handle the large uid? */
2730 if (local_ace->e_id == cpu_to_le32(-1)) {
2731 /* Probably no need to le convert -1 on any arch but can not hurt */
2732 cifs_ace->cifs_uid = cpu_to_le64(-1);
2733 } else
2734 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2735 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2736 return rc;
2737}
2738
2739/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2740static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2741 const int buflen, const int acl_type)
2742{
2743 __u16 rc = 0;
2744 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2745 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
2746 int count;
2747 int i;
2748
2749 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2750 return 0;
2751
2752 count = posix_acl_xattr_count((size_t)buflen);
2753 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2754 count, buflen, le32_to_cpu(local_acl->a_version)));
2755 if (le32_to_cpu(local_acl->a_version) != 2) {
2756 cFYI(1, ("unknown POSIX ACL version %d",
2757 le32_to_cpu(local_acl->a_version)));
2758 return 0;
2759 }
2760 cifs_acl->version = cpu_to_le16(1);
2761 if (acl_type == ACL_TYPE_ACCESS)
2762 cifs_acl->access_entry_count = cpu_to_le16(count);
2763 else if (acl_type == ACL_TYPE_DEFAULT)
2764 cifs_acl->default_entry_count = cpu_to_le16(count);
2765 else {
2766 cFYI(1, ("unknown ACL type %d", acl_type));
2767 return 0;
2768 }
2769 for (i = 0; i < count; i++) {
2770 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2771 &local_acl->a_entries[i]);
2772 if (rc != 0) {
2773 /* ACE not converted */
2774 break;
2775 }
2776 }
2777 if (rc == 0) {
2778 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2779 rc += sizeof(struct cifs_posix_acl);
2780 /* BB add check to make sure ACL does not overflow SMB */
2781 }
2782 return rc;
2783}
2784
2785int
2786CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2787 const unsigned char *searchName,
2788 char *acl_inf, const int buflen, const int acl_type,
2789 const struct nls_table *nls_codepage, int remap)
2790{
2791/* SMB_QUERY_POSIX_ACL */
2792 TRANSACTION2_QPI_REQ *pSMB = NULL;
2793 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2794 int rc = 0;
2795 int bytes_returned;
2796 int name_len;
2797 __u16 params, byte_count;
2798
2799 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2800
2801queryAclRetry:
2802 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2803 (void **) &pSMBr);
2804 if (rc)
2805 return rc;
2806
2807 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2808 name_len =
2809 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2810 PATH_MAX, nls_codepage, remap);
2811 name_len++; /* trailing null */
2812 name_len *= 2;
2813 pSMB->FileName[name_len] = 0;
2814 pSMB->FileName[name_len+1] = 0;
2815 } else { /* BB improve the check for buffer overruns BB */
2816 name_len = strnlen(searchName, PATH_MAX);
2817 name_len++; /* trailing null */
2818 strncpy(pSMB->FileName, searchName, name_len);
2819 }
2820
2821 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2822 pSMB->TotalDataCount = 0;
2823 pSMB->MaxParameterCount = cpu_to_le16(2);
2824 /* BB find exact max data count below from sess structure BB */
2825 pSMB->MaxDataCount = cpu_to_le16(4000);
2826 pSMB->MaxSetupCount = 0;
2827 pSMB->Reserved = 0;
2828 pSMB->Flags = 0;
2829 pSMB->Timeout = 0;
2830 pSMB->Reserved2 = 0;
2831 pSMB->ParameterOffset = cpu_to_le16(
2832 offsetof(struct smb_com_transaction2_qpi_req,
2833 InformationLevel) - 4);
2834 pSMB->DataCount = 0;
2835 pSMB->DataOffset = 0;
2836 pSMB->SetupCount = 1;
2837 pSMB->Reserved3 = 0;
2838 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2839 byte_count = params + 1 /* pad */ ;
2840 pSMB->TotalParameterCount = cpu_to_le16(params);
2841 pSMB->ParameterCount = pSMB->TotalParameterCount;
2842 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2843 pSMB->Reserved4 = 0;
2844 pSMB->hdr.smb_buf_length += byte_count;
2845 pSMB->ByteCount = cpu_to_le16(byte_count);
2846
2847 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2848 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2849 cifs_stats_inc(&tcon->num_acl_get);
2850 if (rc) {
2851 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2852 } else {
2853 /* decode response */
2854
2855 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2856 if (rc || (pSMBr->ByteCount < 2))
2857 /* BB also check enough total bytes returned */
2858 rc = -EIO; /* bad smb */
2859 else {
2860 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2861 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2862 rc = cifs_copy_posix_acl(acl_inf,
2863 (char *)&pSMBr->hdr.Protocol+data_offset,
2864 buflen, acl_type, count);
2865 }
2866 }
2867 cifs_buf_release(pSMB);
2868 if (rc == -EAGAIN)
2869 goto queryAclRetry;
2870 return rc;
2871}
2872
2873int
2874CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2875 const unsigned char *fileName,
2876 const char *local_acl, const int buflen,
2877 const int acl_type,
2878 const struct nls_table *nls_codepage, int remap)
2879{
2880 struct smb_com_transaction2_spi_req *pSMB = NULL;
2881 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2882 char *parm_data;
2883 int name_len;
2884 int rc = 0;
2885 int bytes_returned = 0;
2886 __u16 params, byte_count, data_count, param_offset, offset;
2887
2888 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2889setAclRetry:
2890 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2891 (void **) &pSMBr);
2892 if (rc)
2893 return rc;
2894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2895 name_len =
2896 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
2897 PATH_MAX, nls_codepage, remap);
2898 name_len++; /* trailing null */
2899 name_len *= 2;
2900 } else { /* BB improve the check for buffer overruns BB */
2901 name_len = strnlen(fileName, PATH_MAX);
2902 name_len++; /* trailing null */
2903 strncpy(pSMB->FileName, fileName, name_len);
2904 }
2905 params = 6 + name_len;
2906 pSMB->MaxParameterCount = cpu_to_le16(2);
2907 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2908 pSMB->MaxSetupCount = 0;
2909 pSMB->Reserved = 0;
2910 pSMB->Flags = 0;
2911 pSMB->Timeout = 0;
2912 pSMB->Reserved2 = 0;
2913 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2914 InformationLevel) - 4;
2915 offset = param_offset + params;
2916 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2917 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2918
2919 /* convert to on the wire format for POSIX ACL */
2920 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
2921
2922 if (data_count == 0) {
2923 rc = -EOPNOTSUPP;
2924 goto setACLerrorExit;
2925 }
2926 pSMB->DataOffset = cpu_to_le16(offset);
2927 pSMB->SetupCount = 1;
2928 pSMB->Reserved3 = 0;
2929 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2930 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2931 byte_count = 3 /* pad */ + params + data_count;
2932 pSMB->DataCount = cpu_to_le16(data_count);
2933 pSMB->TotalDataCount = pSMB->DataCount;
2934 pSMB->ParameterCount = cpu_to_le16(params);
2935 pSMB->TotalParameterCount = pSMB->ParameterCount;
2936 pSMB->Reserved4 = 0;
2937 pSMB->hdr.smb_buf_length += byte_count;
2938 pSMB->ByteCount = cpu_to_le16(byte_count);
2939 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2940 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2941 if (rc) {
2942 cFYI(1, ("Set POSIX ACL returned %d", rc));
2943 }
2944
2945setACLerrorExit:
2946 cifs_buf_release(pSMB);
2947 if (rc == -EAGAIN)
2948 goto setAclRetry;
2949 return rc;
2950}
2951
2952/* BB fix tabs in this function FIXME BB */
2953int
2954CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2955 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2956{
2957 int rc = 0;
2958 struct smb_t2_qfi_req *pSMB = NULL;
2959 struct smb_t2_qfi_rsp *pSMBr = NULL;
2960 int bytes_returned;
2961 __u16 params, byte_count;
2962
2963 cFYI(1, ("In GetExtAttr"));
2964 if (tcon == NULL)
2965 return -ENODEV;
2966
2967GetExtAttrRetry:
2968 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2969 (void **) &pSMBr);
2970 if (rc)
2971 return rc;
2972
2973 params = 2 /* level */ +2 /* fid */;
2974 pSMB->t2.TotalDataCount = 0;
2975 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2976 /* BB find exact max data count below from sess structure BB */
2977 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2978 pSMB->t2.MaxSetupCount = 0;
2979 pSMB->t2.Reserved = 0;
2980 pSMB->t2.Flags = 0;
2981 pSMB->t2.Timeout = 0;
2982 pSMB->t2.Reserved2 = 0;
2983 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2984 Fid) - 4);
2985 pSMB->t2.DataCount = 0;
2986 pSMB->t2.DataOffset = 0;
2987 pSMB->t2.SetupCount = 1;
2988 pSMB->t2.Reserved3 = 0;
2989 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2990 byte_count = params + 1 /* pad */ ;
2991 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2992 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2993 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2994 pSMB->Pad = 0;
2995 pSMB->Fid = netfid;
2996 pSMB->hdr.smb_buf_length += byte_count;
2997 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2998
2999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3001 if (rc) {
3002 cFYI(1, ("error %d in GetExtAttr", rc));
3003 } else {
3004 /* decode response */
3005 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3006 if (rc || (pSMBr->ByteCount < 2))
3007 /* BB also check enough total bytes returned */
3008 /* If rc should we check for EOPNOSUPP and
3009 disable the srvino flag? or in caller? */
3010 rc = -EIO; /* bad smb */
3011 else {
3012 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3013 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3014 struct file_chattr_info *pfinfo;
3015 /* BB Do we need a cast or hash here ? */
3016 if (count != 16) {
3017 cFYI(1, ("Illegal size ret in GetExtAttr"));
3018 rc = -EIO;
3019 goto GetExtAttrOut;
3020 }
3021 pfinfo = (struct file_chattr_info *)
3022 (data_offset + (char *) &pSMBr->hdr.Protocol);
3023 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
3024 *pMask = le64_to_cpu(pfinfo->mask);
3025 }
3026 }
3027GetExtAttrOut:
3028 cifs_buf_release(pSMB);
3029 if (rc == -EAGAIN)
3030 goto GetExtAttrRetry;
3031 return rc;
3032}
3033
3034#endif /* CONFIG_POSIX */
3035
3036
3037/* security id for everyone */
3038static const struct cifs_sid sid_everyone =
3039 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
3040/* group users */
3041static const struct cifs_sid sid_user =
3042 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
3043
3044/* Convert CIFS ACL to POSIX form */
3045static int parse_sec_desc(struct cifs_sid *psec_desc, int acl_len)
3046{
3047 return 0;
3048}
3049
3050/* Get Security Descriptor (by handle) from remote server for a file or dir */
3051int
3052CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3053 /* BB fix up return info */ char *acl_inf, const int buflen,
3054 const int acl_type /* ACCESS/DEFAULT not sure implication */)
3055{
3056 int rc = 0;
3057 int buf_type = 0;
3058 QUERY_SEC_DESC_REQ * pSMB;
3059 struct kvec iov[1];
3060
3061 cFYI(1, ("GetCifsACL"));
3062
3063 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3064 8 /* parm len */, tcon, (void **) &pSMB);
3065 if (rc)
3066 return rc;
3067
3068 pSMB->MaxParameterCount = cpu_to_le32(4);
3069 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3070 pSMB->MaxSetupCount = 0;
3071 pSMB->Fid = fid; /* file handle always le */
3072 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3073 CIFS_ACL_DACL);
3074 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3075 pSMB->hdr.smb_buf_length += 11;
3076 iov[0].iov_base = (char *)pSMB;
3077 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3078
3079 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
3080 cifs_stats_inc(&tcon->num_acl_get);
3081 if (rc) {
3082 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3083 } else { /* decode response */
3084 struct cifs_sid *psec_desc;
3085 __le32 * parm;
3086 int parm_len;
3087 int data_len;
3088 int acl_len;
3089 struct smb_com_ntransact_rsp *pSMBr;
3090
3091/* validate_nttransact */
3092 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3093 (char **)&psec_desc,
3094 &parm_len, &data_len);
3095 if (rc)
3096 goto qsec_out;
3097 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3098
3099 cERROR(1, ("smb %p parm %p data %p",
3100 pSMBr, parm, psec_desc)); /* BB removeme BB */
3101
3102 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3103 rc = -EIO; /* bad smb */
3104 goto qsec_out;
3105 }
3106
3107/* BB check that data area is minimum length and as big as acl_len */
3108
3109 acl_len = le32_to_cpu(*(__le32 *)parm);
3110 /* BB check if (acl_len > bufsize) */
3111
3112 parse_sec_desc(psec_desc, acl_len);
3113 }
3114qsec_out:
3115 if (buf_type == CIFS_SMALL_BUFFER)
3116 cifs_small_buf_release(iov[0].iov_base);
3117 else if (buf_type == CIFS_LARGE_BUFFER)
3118 cifs_buf_release(iov[0].iov_base);
3119/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
3120 return rc;
3121}
3122
3123/* Legacy Query Path Information call for lookup to old servers such
3124 as Win9x/WinME */
3125int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3126 const unsigned char *searchName,
3127 FILE_ALL_INFO *pFinfo,
3128 const struct nls_table *nls_codepage, int remap)
3129{
3130 QUERY_INFORMATION_REQ * pSMB;
3131 QUERY_INFORMATION_RSP * pSMBr;
3132 int rc = 0;
3133 int bytes_returned;
3134 int name_len;
3135
3136 cFYI(1, ("In SMBQPath path %s", searchName));
3137QInfRetry:
3138 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3139 (void **) &pSMBr);
3140 if (rc)
3141 return rc;
3142
3143 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3144 name_len =
3145 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3146 PATH_MAX, nls_codepage, remap);
3147 name_len++; /* trailing null */
3148 name_len *= 2;
3149 } else {
3150 name_len = strnlen(searchName, PATH_MAX);
3151 name_len++; /* trailing null */
3152 strncpy(pSMB->FileName, searchName, name_len);
3153 }
3154 pSMB->BufferFormat = 0x04;
3155 name_len++; /* account for buffer type byte */
3156 pSMB->hdr.smb_buf_length += (__u16) name_len;
3157 pSMB->ByteCount = cpu_to_le16(name_len);
3158
3159 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3160 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3161 if (rc) {
3162 cFYI(1, ("Send error in QueryInfo = %d", rc));
3163 } else if (pFinfo) { /* decode response */
3164 struct timespec ts;
3165 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3166 /* BB FIXME - add time zone adjustment BB */
3167 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
3168 ts.tv_nsec = 0;
3169 ts.tv_sec = time;
3170 /* decode time fields */
3171 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3172 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3173 pFinfo->LastAccessTime = 0;
3174 pFinfo->AllocationSize =
3175 cpu_to_le64(le32_to_cpu(pSMBr->size));
3176 pFinfo->EndOfFile = pFinfo->AllocationSize;
3177 pFinfo->Attributes =
3178 cpu_to_le32(le16_to_cpu(pSMBr->attr));
3179 } else
3180 rc = -EIO; /* bad buffer passed in */
3181
3182 cifs_buf_release(pSMB);
3183
3184 if (rc == -EAGAIN)
3185 goto QInfRetry;
3186
3187 return rc;
3188}
3189
3190
3191
3192
3193int
3194CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3195 const unsigned char *searchName,
3196 FILE_ALL_INFO * pFindData,
3197 int legacy /* old style infolevel */,
3198 const struct nls_table *nls_codepage, int remap)
3199{
3200/* level 263 SMB_QUERY_FILE_ALL_INFO */
3201 TRANSACTION2_QPI_REQ *pSMB = NULL;
3202 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3203 int rc = 0;
3204 int bytes_returned;
3205 int name_len;
3206 __u16 params, byte_count;
3207
3208/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3209QPathInfoRetry:
3210 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3211 (void **) &pSMBr);
3212 if (rc)
3213 return rc;
3214
3215 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3216 name_len =
3217 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3218 PATH_MAX, nls_codepage, remap);
3219 name_len++; /* trailing null */
3220 name_len *= 2;
3221 } else { /* BB improve the check for buffer overruns BB */
3222 name_len = strnlen(searchName, PATH_MAX);
3223 name_len++; /* trailing null */
3224 strncpy(pSMB->FileName, searchName, name_len);
3225 }
3226
3227 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3228 pSMB->TotalDataCount = 0;
3229 pSMB->MaxParameterCount = cpu_to_le16(2);
3230 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3231 pSMB->MaxSetupCount = 0;
3232 pSMB->Reserved = 0;
3233 pSMB->Flags = 0;
3234 pSMB->Timeout = 0;
3235 pSMB->Reserved2 = 0;
3236 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3237 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3238 pSMB->DataCount = 0;
3239 pSMB->DataOffset = 0;
3240 pSMB->SetupCount = 1;
3241 pSMB->Reserved3 = 0;
3242 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3243 byte_count = params + 1 /* pad */ ;
3244 pSMB->TotalParameterCount = cpu_to_le16(params);
3245 pSMB->ParameterCount = pSMB->TotalParameterCount;
3246 if (legacy)
3247 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3248 else
3249 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3250 pSMB->Reserved4 = 0;
3251 pSMB->hdr.smb_buf_length += byte_count;
3252 pSMB->ByteCount = cpu_to_le16(byte_count);
3253
3254 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3255 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3256 if (rc) {
3257 cFYI(1, ("Send error in QPathInfo = %d", rc));
3258 } else { /* decode response */
3259 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3260
3261 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3262 rc = -EIO;
3263 else if (!legacy && (pSMBr->ByteCount < 40))
3264 rc = -EIO; /* bad smb */
3265 else if (legacy && (pSMBr->ByteCount < 24))
3266 rc = -EIO; /* 24 or 26 expected but we do not read
3267 last field */
3268 else if (pFindData) {
3269 int size;
3270 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3271 if (legacy) /* we do not read the last field, EAsize,
3272 fortunately since it varies by subdialect
3273 and on Set vs. Get, is two bytes or 4
3274 bytes depending but we don't care here */
3275 size = sizeof(FILE_INFO_STANDARD);
3276 else
3277 size = sizeof(FILE_ALL_INFO);
3278 memcpy((char *) pFindData,
3279 (char *) &pSMBr->hdr.Protocol +
3280 data_offset, size);
3281 } else
3282 rc = -ENOMEM;
3283 }
3284 cifs_buf_release(pSMB);
3285 if (rc == -EAGAIN)
3286 goto QPathInfoRetry;
3287
3288 return rc;
3289}
3290
3291int
3292CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3293 const unsigned char *searchName,
3294 FILE_UNIX_BASIC_INFO * pFindData,
3295 const struct nls_table *nls_codepage, int remap)
3296{
3297/* SMB_QUERY_FILE_UNIX_BASIC */
3298 TRANSACTION2_QPI_REQ *pSMB = NULL;
3299 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3300 int rc = 0;
3301 int bytes_returned = 0;
3302 int name_len;
3303 __u16 params, byte_count;
3304
3305 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3306UnixQPathInfoRetry:
3307 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3308 (void **) &pSMBr);
3309 if (rc)
3310 return rc;
3311
3312 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3313 name_len =
3314 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3315 PATH_MAX, nls_codepage, remap);
3316 name_len++; /* trailing null */
3317 name_len *= 2;
3318 } else { /* BB improve the check for buffer overruns BB */
3319 name_len = strnlen(searchName, PATH_MAX);
3320 name_len++; /* trailing null */
3321 strncpy(pSMB->FileName, searchName, name_len);
3322 }
3323
3324 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
3325 pSMB->TotalDataCount = 0;
3326 pSMB->MaxParameterCount = cpu_to_le16(2);
3327 /* BB find exact max SMB PDU from sess structure BB */
3328 pSMB->MaxDataCount = cpu_to_le16(4000);
3329 pSMB->MaxSetupCount = 0;
3330 pSMB->Reserved = 0;
3331 pSMB->Flags = 0;
3332 pSMB->Timeout = 0;
3333 pSMB->Reserved2 = 0;
3334 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3335 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3336 pSMB->DataCount = 0;
3337 pSMB->DataOffset = 0;
3338 pSMB->SetupCount = 1;
3339 pSMB->Reserved3 = 0;
3340 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3341 byte_count = params + 1 /* pad */ ;
3342 pSMB->TotalParameterCount = cpu_to_le16(params);
3343 pSMB->ParameterCount = pSMB->TotalParameterCount;
3344 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3345 pSMB->Reserved4 = 0;
3346 pSMB->hdr.smb_buf_length += byte_count;
3347 pSMB->ByteCount = cpu_to_le16(byte_count);
3348
3349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3351 if (rc) {
3352 cFYI(1, ("Send error in QPathInfo = %d", rc));
3353 } else { /* decode response */
3354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3355
3356 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3357 rc = -EIO; /* bad smb */
3358 } else {
3359 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3360 memcpy((char *) pFindData,
3361 (char *) &pSMBr->hdr.Protocol +
3362 data_offset,
3363 sizeof (FILE_UNIX_BASIC_INFO));
3364 }
3365 }
3366 cifs_buf_release(pSMB);
3367 if (rc == -EAGAIN)
3368 goto UnixQPathInfoRetry;
3369
3370 return rc;
3371}
3372
3373#if 0 /* function unused at present */
3374int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3375 const char *searchName, FILE_ALL_INFO * findData,
3376 const struct nls_table *nls_codepage)
3377{
3378/* level 257 SMB_ */
3379 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3380 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3381 int rc = 0;
3382 int bytes_returned;
3383 int name_len;
3384 __u16 params, byte_count;
3385
3386 cFYI(1, ("In FindUnique"));
3387findUniqueRetry:
3388 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3389 (void **) &pSMBr);
3390 if (rc)
3391 return rc;
3392
3393 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3394 name_len =
3395 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3396 PATH_MAX, nls_codepage);
3397 name_len++; /* trailing null */
3398 name_len *= 2;
3399 } else { /* BB improve the check for buffer overruns BB */
3400 name_len = strnlen(searchName, PATH_MAX);
3401 name_len++; /* trailing null */
3402 strncpy(pSMB->FileName, searchName, name_len);
3403 }
3404
3405 params = 12 + name_len /* includes null */ ;
3406 pSMB->TotalDataCount = 0; /* no EAs */
3407 pSMB->MaxParameterCount = cpu_to_le16(2);
3408 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3409 pSMB->MaxSetupCount = 0;
3410 pSMB->Reserved = 0;
3411 pSMB->Flags = 0;
3412 pSMB->Timeout = 0;
3413 pSMB->Reserved2 = 0;
3414 pSMB->ParameterOffset = cpu_to_le16(
3415 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
3416 pSMB->DataCount = 0;
3417 pSMB->DataOffset = 0;
3418 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3419 pSMB->Reserved3 = 0;
3420 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3421 byte_count = params + 1 /* pad */ ;
3422 pSMB->TotalParameterCount = cpu_to_le16(params);
3423 pSMB->ParameterCount = pSMB->TotalParameterCount;
3424 pSMB->SearchAttributes =
3425 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3426 ATTR_DIRECTORY);
3427 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3428 pSMB->SearchFlags = cpu_to_le16(1);
3429 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3430 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3431 pSMB->hdr.smb_buf_length += byte_count;
3432 pSMB->ByteCount = cpu_to_le16(byte_count);
3433
3434 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3435 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3436
3437 if (rc) {
3438 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3439 } else { /* decode response */
3440 cifs_stats_inc(&tcon->num_ffirst);
3441 /* BB fill in */
3442 }
3443
3444 cifs_buf_release(pSMB);
3445 if (rc == -EAGAIN)
3446 goto findUniqueRetry;
3447
3448 return rc;
3449}
3450#endif /* end unused (temporarily) function */
3451
3452/* xid, tcon, searchName and codepage are input parms, rest are returned */
3453int
3454CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3455 const char *searchName,
3456 const struct nls_table *nls_codepage,
3457 __u16 *pnetfid,
3458 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
3459{
3460/* level 257 SMB_ */
3461 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3462 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3463 T2_FFIRST_RSP_PARMS * parms;
3464 int rc = 0;
3465 int bytes_returned = 0;
3466 int name_len;
3467 __u16 params, byte_count;
3468
3469 cFYI(1, ("In FindFirst for %s", searchName));
3470
3471findFirstRetry:
3472 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3473 (void **) &pSMBr);
3474 if (rc)
3475 return rc;
3476
3477 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3478 name_len =
3479 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3480 PATH_MAX, nls_codepage, remap);
3481 /* We can not add the asterik earlier in case
3482 it got remapped to 0xF03A as if it were part of the
3483 directory name instead of a wildcard */
3484 name_len *= 2;
3485 pSMB->FileName[name_len] = dirsep;
3486 pSMB->FileName[name_len+1] = 0;
3487 pSMB->FileName[name_len+2] = '*';
3488 pSMB->FileName[name_len+3] = 0;
3489 name_len += 4; /* now the trailing null */
3490 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3491 pSMB->FileName[name_len+1] = 0;
3492 name_len += 2;
3493 } else { /* BB add check for overrun of SMB buf BB */
3494 name_len = strnlen(searchName, PATH_MAX);
3495/* BB fix here and in unicode clause above ie
3496 if (name_len > buffersize-header)
3497 free buffer exit; BB */
3498 strncpy(pSMB->FileName, searchName, name_len);
3499 pSMB->FileName[name_len] = dirsep;
3500 pSMB->FileName[name_len+1] = '*';
3501 pSMB->FileName[name_len+2] = 0;
3502 name_len += 3;
3503 }
3504
3505 params = 12 + name_len /* includes null */ ;
3506 pSMB->TotalDataCount = 0; /* no EAs */
3507 pSMB->MaxParameterCount = cpu_to_le16(10);
3508 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3509 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3510 pSMB->MaxSetupCount = 0;
3511 pSMB->Reserved = 0;
3512 pSMB->Flags = 0;
3513 pSMB->Timeout = 0;
3514 pSMB->Reserved2 = 0;
3515 byte_count = params + 1 /* pad */ ;
3516 pSMB->TotalParameterCount = cpu_to_le16(params);
3517 pSMB->ParameterCount = pSMB->TotalParameterCount;
3518 pSMB->ParameterOffset = cpu_to_le16(
3519 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3520 - 4);
3521 pSMB->DataCount = 0;
3522 pSMB->DataOffset = 0;
3523 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3524 pSMB->Reserved3 = 0;
3525 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3526 pSMB->SearchAttributes =
3527 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3528 ATTR_DIRECTORY);
3529 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3530 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3531 CIFS_SEARCH_RETURN_RESUME);
3532 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3533
3534 /* BB what should we set StorageType to? Does it matter? BB */
3535 pSMB->SearchStorageType = 0;
3536 pSMB->hdr.smb_buf_length += byte_count;
3537 pSMB->ByteCount = cpu_to_le16(byte_count);
3538
3539 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3540 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3541 cifs_stats_inc(&tcon->num_ffirst);
3542
3543 if (rc) {/* BB add logic to retry regular search if Unix search
3544 rejected unexpectedly by server */
3545 /* BB Add code to handle unsupported level rc */
3546 cFYI(1, ("Error in FindFirst = %d", rc));
3547
3548 cifs_buf_release(pSMB);
3549
3550 /* BB eventually could optimize out free and realloc of buf */
3551 /* for this case */
3552 if (rc == -EAGAIN)
3553 goto findFirstRetry;
3554 } else { /* decode response */
3555 /* BB remember to free buffer if error BB */
3556 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3557 if (rc == 0) {
3558 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3559 psrch_inf->unicode = TRUE;
3560 else
3561 psrch_inf->unicode = FALSE;
3562
3563 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3564 psrch_inf->smallBuf = 0;
3565 psrch_inf->srch_entries_start =
3566 (char *) &pSMBr->hdr.Protocol +
3567 le16_to_cpu(pSMBr->t2.DataOffset);
3568 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3569 le16_to_cpu(pSMBr->t2.ParameterOffset));
3570
3571 if (parms->EndofSearch)
3572 psrch_inf->endOfSearch = TRUE;
3573 else
3574 psrch_inf->endOfSearch = FALSE;
3575
3576 psrch_inf->entries_in_buffer =
3577 le16_to_cpu(parms->SearchCount);
3578 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
3579 psrch_inf->entries_in_buffer;
3580 *pnetfid = parms->SearchHandle;
3581 } else {
3582 cifs_buf_release(pSMB);
3583 }
3584 }
3585
3586 return rc;
3587}
3588
3589int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3590 __u16 searchHandle, struct cifs_search_info *psrch_inf)
3591{
3592 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3593 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3594 T2_FNEXT_RSP_PARMS * parms;
3595 char *response_data;
3596 int rc = 0;
3597 int bytes_returned, name_len;
3598 __u16 params, byte_count;
3599
3600 cFYI(1, ("In FindNext"));
3601
3602 if (psrch_inf->endOfSearch == TRUE)
3603 return -ENOENT;
3604
3605 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3606 (void **) &pSMBr);
3607 if (rc)
3608 return rc;
3609
3610 params = 14; /* includes 2 bytes of null string, converted to LE below*/
3611 byte_count = 0;
3612 pSMB->TotalDataCount = 0; /* no EAs */
3613 pSMB->MaxParameterCount = cpu_to_le16(8);
3614 pSMB->MaxDataCount =
3615 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3616 0xFFFFFF00);
3617 pSMB->MaxSetupCount = 0;
3618 pSMB->Reserved = 0;
3619 pSMB->Flags = 0;
3620 pSMB->Timeout = 0;
3621 pSMB->Reserved2 = 0;
3622 pSMB->ParameterOffset = cpu_to_le16(
3623 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3624 pSMB->DataCount = 0;
3625 pSMB->DataOffset = 0;
3626 pSMB->SetupCount = 1;
3627 pSMB->Reserved3 = 0;
3628 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3629 pSMB->SearchHandle = searchHandle; /* always kept as le */
3630 pSMB->SearchCount =
3631 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3632 /* test for Unix extensions */
3633/* if (tcon->ses->capabilities & CAP_UNIX) {
3634 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3635 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3636 } else {
3637 pSMB->InformationLevel =
3638 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3639 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3640 } */
3641 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3642 pSMB->ResumeKey = psrch_inf->resume_key;
3643 pSMB->SearchFlags =
3644 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3645
3646 name_len = psrch_inf->resume_name_len;
3647 params += name_len;
3648 if (name_len < PATH_MAX) {
3649 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3650 byte_count += name_len;
3651 /* 14 byte parm len above enough for 2 byte null terminator */
3652 pSMB->ResumeFileName[name_len] = 0;
3653 pSMB->ResumeFileName[name_len+1] = 0;
3654 } else {
3655 rc = -EINVAL;
3656 goto FNext2_err_exit;
3657 }
3658 byte_count = params + 1 /* pad */ ;
3659 pSMB->TotalParameterCount = cpu_to_le16(params);
3660 pSMB->ParameterCount = pSMB->TotalParameterCount;
3661 pSMB->hdr.smb_buf_length += byte_count;
3662 pSMB->ByteCount = cpu_to_le16(byte_count);
3663
3664 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3665 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3666 cifs_stats_inc(&tcon->num_fnext);
3667 if (rc) {
3668 if (rc == -EBADF) {
3669 psrch_inf->endOfSearch = TRUE;
3670 rc = 0; /* search probably was closed at end of search*/
3671 } else
3672 cFYI(1, ("FindNext returned = %d", rc));
3673 } else { /* decode response */
3674 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3675
3676 if (rc == 0) {
3677 /* BB fixme add lock for file (srch_info) struct here */
3678 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3679 psrch_inf->unicode = TRUE;
3680 else
3681 psrch_inf->unicode = FALSE;
3682 response_data = (char *) &pSMBr->hdr.Protocol +
3683 le16_to_cpu(pSMBr->t2.ParameterOffset);
3684 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3685 response_data = (char *)&pSMBr->hdr.Protocol +
3686 le16_to_cpu(pSMBr->t2.DataOffset);
3687 if (psrch_inf->smallBuf)
3688 cifs_small_buf_release(
3689 psrch_inf->ntwrk_buf_start);
3690 else
3691 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3692 psrch_inf->srch_entries_start = response_data;
3693 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3694 psrch_inf->smallBuf = 0;
3695 if (parms->EndofSearch)
3696 psrch_inf->endOfSearch = TRUE;
3697 else
3698 psrch_inf->endOfSearch = FALSE;
3699 psrch_inf->entries_in_buffer =
3700 le16_to_cpu(parms->SearchCount);
3701 psrch_inf->index_of_last_entry +=
3702 psrch_inf->entries_in_buffer;
3703/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3704 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
3705
3706 /* BB fixme add unlock here */
3707 }
3708
3709 }
3710
3711 /* BB On error, should we leave previous search buf (and count and
3712 last entry fields) intact or free the previous one? */
3713
3714 /* Note: On -EAGAIN error only caller can retry on handle based calls
3715 since file handle passed in no longer valid */
3716FNext2_err_exit:
3717 if (rc != 0)
3718 cifs_buf_release(pSMB);
3719 return rc;
3720}
3721
3722int
3723CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3724 const __u16 searchHandle)
3725{
3726 int rc = 0;
3727 FINDCLOSE_REQ *pSMB = NULL;
3728 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3729 int bytes_returned;
3730
3731 cFYI(1, ("In CIFSSMBFindClose"));
3732 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3733
3734 /* no sense returning error if session restarted
3735 as file handle has been closed */
3736 if (rc == -EAGAIN)
3737 return 0;
3738 if (rc)
3739 return rc;
3740
3741 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3742 pSMB->FileID = searchHandle;
3743 pSMB->ByteCount = 0;
3744 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3745 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3746 if (rc) {
3747 cERROR(1, ("Send error in FindClose = %d", rc));
3748 }
3749 cifs_stats_inc(&tcon->num_fclose);
3750 cifs_small_buf_release(pSMB);
3751
3752 /* Since session is dead, search handle closed on server already */
3753 if (rc == -EAGAIN)
3754 rc = 0;
3755
3756 return rc;
3757}
3758
3759int
3760CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3761 const unsigned char *searchName,
3762 __u64 * inode_number,
3763 const struct nls_table *nls_codepage, int remap)
3764{
3765 int rc = 0;
3766 TRANSACTION2_QPI_REQ *pSMB = NULL;
3767 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3768 int name_len, bytes_returned;
3769 __u16 params, byte_count;
3770
3771 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
3772 if (tcon == NULL)
3773 return -ENODEV;
3774
3775GetInodeNumberRetry:
3776 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3777 (void **) &pSMBr);
3778 if (rc)
3779 return rc;
3780
3781 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3782 name_len =
3783 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3784 PATH_MAX, nls_codepage, remap);
3785 name_len++; /* trailing null */
3786 name_len *= 2;
3787 } else { /* BB improve the check for buffer overruns BB */
3788 name_len = strnlen(searchName, PATH_MAX);
3789 name_len++; /* trailing null */
3790 strncpy(pSMB->FileName, searchName, name_len);
3791 }
3792
3793 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3794 pSMB->TotalDataCount = 0;
3795 pSMB->MaxParameterCount = cpu_to_le16(2);
3796 /* BB find exact max data count below from sess structure BB */
3797 pSMB->MaxDataCount = cpu_to_le16(4000);
3798 pSMB->MaxSetupCount = 0;
3799 pSMB->Reserved = 0;
3800 pSMB->Flags = 0;
3801 pSMB->Timeout = 0;
3802 pSMB->Reserved2 = 0;
3803 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3804 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
3805 pSMB->DataCount = 0;
3806 pSMB->DataOffset = 0;
3807 pSMB->SetupCount = 1;
3808 pSMB->Reserved3 = 0;
3809 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3810 byte_count = params + 1 /* pad */ ;
3811 pSMB->TotalParameterCount = cpu_to_le16(params);
3812 pSMB->ParameterCount = pSMB->TotalParameterCount;
3813 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3814 pSMB->Reserved4 = 0;
3815 pSMB->hdr.smb_buf_length += byte_count;
3816 pSMB->ByteCount = cpu_to_le16(byte_count);
3817
3818 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3819 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3820 if (rc) {
3821 cFYI(1, ("error %d in QueryInternalInfo", rc));
3822 } else {
3823 /* decode response */
3824 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3825 if (rc || (pSMBr->ByteCount < 2))
3826 /* BB also check enough total bytes returned */
3827 /* If rc should we check for EOPNOSUPP and
3828 disable the srvino flag? or in caller? */
3829 rc = -EIO; /* bad smb */
3830 else {
3831 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3832 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3833 struct file_internal_info *pfinfo;
3834 /* BB Do we need a cast or hash here ? */
3835 if (count < 8) {
3836 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3837 rc = -EIO;
3838 goto GetInodeNumOut;
3839 }
3840 pfinfo = (struct file_internal_info *)
3841 (data_offset + (char *) &pSMBr->hdr.Protocol);
3842 *inode_number = pfinfo->UniqueId;
3843 }
3844 }
3845GetInodeNumOut:
3846 cifs_buf_release(pSMB);
3847 if (rc == -EAGAIN)
3848 goto GetInodeNumberRetry;
3849 return rc;
3850}
3851
3852int
3853CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3854 const unsigned char *searchName,
3855 unsigned char **targetUNCs,
3856 unsigned int *number_of_UNC_in_array,
3857 const struct nls_table *nls_codepage, int remap)
3858{
3859/* TRANS2_GET_DFS_REFERRAL */
3860 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3861 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3862 struct dfs_referral_level_3 *referrals = NULL;
3863 int rc = 0;
3864 int bytes_returned;
3865 int name_len;
3866 unsigned int i;
3867 char *temp;
3868 __u16 params, byte_count;
3869 *number_of_UNC_in_array = 0;
3870 *targetUNCs = NULL;
3871
3872 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3873 if (ses == NULL)
3874 return -ENODEV;
3875getDFSRetry:
3876 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3877 (void **) &pSMBr);
3878 if (rc)
3879 return rc;
3880
3881 /* server pointer checked in called function,
3882 but should never be null here anyway */
3883 pSMB->hdr.Mid = GetNextMid(ses->server);
3884 pSMB->hdr.Tid = ses->ipc_tid;
3885 pSMB->hdr.Uid = ses->Suid;
3886 if (ses->capabilities & CAP_STATUS32) {
3887 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3888 }
3889 if (ses->capabilities & CAP_DFS) {
3890 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3891 }
3892
3893 if (ses->capabilities & CAP_UNICODE) {
3894 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3895 name_len =
3896 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3897 searchName, PATH_MAX, nls_codepage, remap);
3898 name_len++; /* trailing null */
3899 name_len *= 2;
3900 } else { /* BB improve the check for buffer overruns BB */
3901 name_len = strnlen(searchName, PATH_MAX);
3902 name_len++; /* trailing null */
3903 strncpy(pSMB->RequestFileName, searchName, name_len);
3904 }
3905
3906 if (ses->server) {
3907 if (ses->server->secMode &
3908 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3909 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3910 }
3911
3912 pSMB->hdr.Uid = ses->Suid;
3913
3914 params = 2 /* level */ + name_len /*includes null */ ;
3915 pSMB->TotalDataCount = 0;
3916 pSMB->DataCount = 0;
3917 pSMB->DataOffset = 0;
3918 pSMB->MaxParameterCount = 0;
3919 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3920 pSMB->MaxSetupCount = 0;
3921 pSMB->Reserved = 0;
3922 pSMB->Flags = 0;
3923 pSMB->Timeout = 0;
3924 pSMB->Reserved2 = 0;
3925 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3926 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3927 pSMB->SetupCount = 1;
3928 pSMB->Reserved3 = 0;
3929 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3930 byte_count = params + 3 /* pad */ ;
3931 pSMB->ParameterCount = cpu_to_le16(params);
3932 pSMB->TotalParameterCount = pSMB->ParameterCount;
3933 pSMB->MaxReferralLevel = cpu_to_le16(3);
3934 pSMB->hdr.smb_buf_length += byte_count;
3935 pSMB->ByteCount = cpu_to_le16(byte_count);
3936
3937 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3938 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3939 if (rc) {
3940 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3941 } else { /* decode response */
3942/* BB Add logic to parse referrals here */
3943 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3944
3945 /* BB Also check if enough total bytes returned? */
3946 if (rc || (pSMBr->ByteCount < 17))
3947 rc = -EIO; /* bad smb */
3948 else {
3949 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3950 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3951
3952 cFYI(1,
3953 ("Decoding GetDFSRefer response BCC: %d Offset %d",
3954 pSMBr->ByteCount, data_offset));
3955 referrals =
3956 (struct dfs_referral_level_3 *)
3957 (8 /* sizeof start of data block */ +
3958 data_offset +
3959 (char *) &pSMBr->hdr.Protocol);
3960 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",
3961 le16_to_cpu(pSMBr->NumberOfReferrals),
3962 le16_to_cpu(pSMBr->DFSFlags),
3963 le16_to_cpu(referrals->ReferralSize),
3964 le16_to_cpu(referrals->ServerType),
3965 le16_to_cpu(referrals->ReferralFlags),
3966 le16_to_cpu(referrals->TimeToLive)));
3967 /* BB This field is actually two bytes in from start of
3968 data block so we could do safety check that DataBlock
3969 begins at address of pSMBr->NumberOfReferrals */
3970 *number_of_UNC_in_array =
3971 le16_to_cpu(pSMBr->NumberOfReferrals);
3972
3973 /* BB Fix below so can return more than one referral */
3974 if (*number_of_UNC_in_array > 1)
3975 *number_of_UNC_in_array = 1;
3976
3977 /* get the length of the strings describing refs */
3978 name_len = 0;
3979 for (i = 0; i < *number_of_UNC_in_array; i++) {
3980 /* make sure that DfsPathOffset not past end */
3981 __u16 offset =
3982 le16_to_cpu(referrals->DfsPathOffset);
3983 if (offset > data_count) {
3984 /* if invalid referral, stop here and do
3985 not try to copy any more */
3986 *number_of_UNC_in_array = i;
3987 break;
3988 }
3989 temp = ((char *)referrals) + offset;
3990
3991 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3992 name_len += UniStrnlen((wchar_t *)temp,
3993 data_count);
3994 } else {
3995 name_len += strnlen(temp, data_count);
3996 }
3997 referrals++;
3998 /* BB add check that referral pointer does
3999 not fall off end PDU */
4000 }
4001 /* BB add check for name_len bigger than bcc */
4002 *targetUNCs =
4003 kmalloc(name_len+1+(*number_of_UNC_in_array),
4004 GFP_KERNEL);
4005 if (*targetUNCs == NULL) {
4006 rc = -ENOMEM;
4007 goto GetDFSRefExit;
4008 }
4009 /* copy the ref strings */
4010 referrals = (struct dfs_referral_level_3 *)
4011 (8 /* sizeof data hdr */ + data_offset +
4012 (char *) &pSMBr->hdr.Protocol);
4013
4014 for (i = 0; i < *number_of_UNC_in_array; i++) {
4015 temp = ((char *)referrals) +
4016 le16_to_cpu(referrals->DfsPathOffset);
4017 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4018 cifs_strfromUCS_le(*targetUNCs,
4019 (__le16 *) temp,
4020 name_len,
4021 nls_codepage);
4022 } else {
4023 strncpy(*targetUNCs, temp, name_len);
4024 }
4025 /* BB update target_uncs pointers */
4026 referrals++;
4027 }
4028 temp = *targetUNCs;
4029 temp[name_len] = 0;
4030 }
4031
4032 }
4033GetDFSRefExit:
4034 if (pSMB)
4035 cifs_buf_release(pSMB);
4036
4037 if (rc == -EAGAIN)
4038 goto getDFSRetry;
4039
4040 return rc;
4041}
4042
4043/* Query File System Info such as free space to old servers such as Win 9x */
4044int
4045SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4046{
4047/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4048 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4049 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4050 FILE_SYSTEM_ALLOC_INFO *response_data;
4051 int rc = 0;
4052 int bytes_returned = 0;
4053 __u16 params, byte_count;
4054
4055 cFYI(1, ("OldQFSInfo"));
4056oldQFSInfoRetry:
4057 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4058 (void **) &pSMBr);
4059 if (rc)
4060 return rc;
4061 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4062 (void **) &pSMBr);
4063 if (rc)
4064 return rc;
4065
4066 params = 2; /* level */
4067 pSMB->TotalDataCount = 0;
4068 pSMB->MaxParameterCount = cpu_to_le16(2);
4069 pSMB->MaxDataCount = cpu_to_le16(1000);
4070 pSMB->MaxSetupCount = 0;
4071 pSMB->Reserved = 0;
4072 pSMB->Flags = 0;
4073 pSMB->Timeout = 0;
4074 pSMB->Reserved2 = 0;
4075 byte_count = params + 1 /* pad */ ;
4076 pSMB->TotalParameterCount = cpu_to_le16(params);
4077 pSMB->ParameterCount = pSMB->TotalParameterCount;
4078 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4079 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4080 pSMB->DataCount = 0;
4081 pSMB->DataOffset = 0;
4082 pSMB->SetupCount = 1;
4083 pSMB->Reserved3 = 0;
4084 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4085 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4086 pSMB->hdr.smb_buf_length += byte_count;
4087 pSMB->ByteCount = cpu_to_le16(byte_count);
4088
4089 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4090 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4091 if (rc) {
4092 cFYI(1, ("Send error in QFSInfo = %d", rc));
4093 } else { /* decode response */
4094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4095
4096 if (rc || (pSMBr->ByteCount < 18))
4097 rc = -EIO; /* bad smb */
4098 else {
4099 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4100 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
4101 pSMBr->ByteCount, data_offset));
4102
4103 response_data = (FILE_SYSTEM_ALLOC_INFO *)
4104 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4105 FSData->f_bsize =
4106 le16_to_cpu(response_data->BytesPerSector) *
4107 le32_to_cpu(response_data->
4108 SectorsPerAllocationUnit);
4109 FSData->f_blocks =
4110 le32_to_cpu(response_data->TotalAllocationUnits);
4111 FSData->f_bfree = FSData->f_bavail =
4112 le32_to_cpu(response_data->FreeAllocationUnits);
4113 cFYI(1,
4114 ("Blocks: %lld Free: %lld Block size %ld",
4115 (unsigned long long)FSData->f_blocks,
4116 (unsigned long long)FSData->f_bfree,
4117 FSData->f_bsize));
4118 }
4119 }
4120 cifs_buf_release(pSMB);
4121
4122 if (rc == -EAGAIN)
4123 goto oldQFSInfoRetry;
4124
4125 return rc;
4126}
4127
4128int
4129CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4130{
4131/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4132 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4133 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4134 FILE_SYSTEM_INFO *response_data;
4135 int rc = 0;
4136 int bytes_returned = 0;
4137 __u16 params, byte_count;
4138
4139 cFYI(1, ("In QFSInfo"));
4140QFSInfoRetry:
4141 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4142 (void **) &pSMBr);
4143 if (rc)
4144 return rc;
4145
4146 params = 2; /* level */
4147 pSMB->TotalDataCount = 0;
4148 pSMB->MaxParameterCount = cpu_to_le16(2);
4149 pSMB->MaxDataCount = cpu_to_le16(1000);
4150 pSMB->MaxSetupCount = 0;
4151 pSMB->Reserved = 0;
4152 pSMB->Flags = 0;
4153 pSMB->Timeout = 0;
4154 pSMB->Reserved2 = 0;
4155 byte_count = params + 1 /* pad */ ;
4156 pSMB->TotalParameterCount = cpu_to_le16(params);
4157 pSMB->ParameterCount = pSMB->TotalParameterCount;
4158 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4159 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4160 pSMB->DataCount = 0;
4161 pSMB->DataOffset = 0;
4162 pSMB->SetupCount = 1;
4163 pSMB->Reserved3 = 0;
4164 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4165 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4166 pSMB->hdr.smb_buf_length += byte_count;
4167 pSMB->ByteCount = cpu_to_le16(byte_count);
4168
4169 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4170 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4171 if (rc) {
4172 cFYI(1, ("Send error in QFSInfo = %d", rc));
4173 } else { /* decode response */
4174 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4175
4176 if (rc || (pSMBr->ByteCount < 24))
4177 rc = -EIO; /* bad smb */
4178 else {
4179 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4180
4181 response_data =
4182 (FILE_SYSTEM_INFO
4183 *) (((char *) &pSMBr->hdr.Protocol) +
4184 data_offset);
4185 FSData->f_bsize =
4186 le32_to_cpu(response_data->BytesPerSector) *
4187 le32_to_cpu(response_data->
4188 SectorsPerAllocationUnit);
4189 FSData->f_blocks =
4190 le64_to_cpu(response_data->TotalAllocationUnits);
4191 FSData->f_bfree = FSData->f_bavail =
4192 le64_to_cpu(response_data->FreeAllocationUnits);
4193 cFYI(1,
4194 ("Blocks: %lld Free: %lld Block size %ld",
4195 (unsigned long long)FSData->f_blocks,
4196 (unsigned long long)FSData->f_bfree,
4197 FSData->f_bsize));
4198 }
4199 }
4200 cifs_buf_release(pSMB);
4201
4202 if (rc == -EAGAIN)
4203 goto QFSInfoRetry;
4204
4205 return rc;
4206}
4207
4208int
4209CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
4210{
4211/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4212 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4213 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4214 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4215 int rc = 0;
4216 int bytes_returned = 0;
4217 __u16 params, byte_count;
4218
4219 cFYI(1, ("In QFSAttributeInfo"));
4220QFSAttributeRetry:
4221 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4222 (void **) &pSMBr);
4223 if (rc)
4224 return rc;
4225
4226 params = 2; /* level */
4227 pSMB->TotalDataCount = 0;
4228 pSMB->MaxParameterCount = cpu_to_le16(2);
4229 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4230 pSMB->MaxSetupCount = 0;
4231 pSMB->Reserved = 0;
4232 pSMB->Flags = 0;
4233 pSMB->Timeout = 0;
4234 pSMB->Reserved2 = 0;
4235 byte_count = params + 1 /* pad */ ;
4236 pSMB->TotalParameterCount = cpu_to_le16(params);
4237 pSMB->ParameterCount = pSMB->TotalParameterCount;
4238 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4239 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4240 pSMB->DataCount = 0;
4241 pSMB->DataOffset = 0;
4242 pSMB->SetupCount = 1;
4243 pSMB->Reserved3 = 0;
4244 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4245 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4246 pSMB->hdr.smb_buf_length += byte_count;
4247 pSMB->ByteCount = cpu_to_le16(byte_count);
4248
4249 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4250 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4251 if (rc) {
4252 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4253 } else { /* decode response */
4254 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4255
4256 if (rc || (pSMBr->ByteCount < 13)) {
4257 /* BB also check if enough bytes returned */
4258 rc = -EIO; /* bad smb */
4259 } else {
4260 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4261 response_data =
4262 (FILE_SYSTEM_ATTRIBUTE_INFO
4263 *) (((char *) &pSMBr->hdr.Protocol) +
4264 data_offset);
4265 memcpy(&tcon->fsAttrInfo, response_data,
4266 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4267 }
4268 }
4269 cifs_buf_release(pSMB);
4270
4271 if (rc == -EAGAIN)
4272 goto QFSAttributeRetry;
4273
4274 return rc;
4275}
4276
4277int
4278CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
4279{
4280/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4281 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4282 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4283 FILE_SYSTEM_DEVICE_INFO *response_data;
4284 int rc = 0;
4285 int bytes_returned = 0;
4286 __u16 params, byte_count;
4287
4288 cFYI(1, ("In QFSDeviceInfo"));
4289QFSDeviceRetry:
4290 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4291 (void **) &pSMBr);
4292 if (rc)
4293 return rc;
4294
4295 params = 2; /* level */
4296 pSMB->TotalDataCount = 0;
4297 pSMB->MaxParameterCount = cpu_to_le16(2);
4298 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4299 pSMB->MaxSetupCount = 0;
4300 pSMB->Reserved = 0;
4301 pSMB->Flags = 0;
4302 pSMB->Timeout = 0;
4303 pSMB->Reserved2 = 0;
4304 byte_count = params + 1 /* pad */ ;
4305 pSMB->TotalParameterCount = cpu_to_le16(params);
4306 pSMB->ParameterCount = pSMB->TotalParameterCount;
4307 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4308 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4309
4310 pSMB->DataCount = 0;
4311 pSMB->DataOffset = 0;
4312 pSMB->SetupCount = 1;
4313 pSMB->Reserved3 = 0;
4314 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4315 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4316 pSMB->hdr.smb_buf_length += byte_count;
4317 pSMB->ByteCount = cpu_to_le16(byte_count);
4318
4319 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4320 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4321 if (rc) {
4322 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4323 } else { /* decode response */
4324 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4325
4326 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4327 rc = -EIO; /* bad smb */
4328 else {
4329 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4330 response_data =
4331 (FILE_SYSTEM_DEVICE_INFO *)
4332 (((char *) &pSMBr->hdr.Protocol) +
4333 data_offset);
4334 memcpy(&tcon->fsDevInfo, response_data,
4335 sizeof (FILE_SYSTEM_DEVICE_INFO));
4336 }
4337 }
4338 cifs_buf_release(pSMB);
4339
4340 if (rc == -EAGAIN)
4341 goto QFSDeviceRetry;
4342
4343 return rc;
4344}
4345
4346int
4347CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
4348{
4349/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4350 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4351 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4352 FILE_SYSTEM_UNIX_INFO *response_data;
4353 int rc = 0;
4354 int bytes_returned = 0;
4355 __u16 params, byte_count;
4356
4357 cFYI(1, ("In QFSUnixInfo"));
4358QFSUnixRetry:
4359 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4360 (void **) &pSMBr);
4361 if (rc)
4362 return rc;
4363
4364 params = 2; /* level */
4365 pSMB->TotalDataCount = 0;
4366 pSMB->DataCount = 0;
4367 pSMB->DataOffset = 0;
4368 pSMB->MaxParameterCount = cpu_to_le16(2);
4369 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4370 pSMB->MaxSetupCount = 0;
4371 pSMB->Reserved = 0;
4372 pSMB->Flags = 0;
4373 pSMB->Timeout = 0;
4374 pSMB->Reserved2 = 0;
4375 byte_count = params + 1 /* pad */ ;
4376 pSMB->ParameterCount = cpu_to_le16(params);
4377 pSMB->TotalParameterCount = pSMB->ParameterCount;
4378 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4379 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4380 pSMB->SetupCount = 1;
4381 pSMB->Reserved3 = 0;
4382 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4383 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4384 pSMB->hdr.smb_buf_length += byte_count;
4385 pSMB->ByteCount = cpu_to_le16(byte_count);
4386
4387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4388 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4389 if (rc) {
4390 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4391 } else { /* decode response */
4392 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4393
4394 if (rc || (pSMBr->ByteCount < 13)) {
4395 rc = -EIO; /* bad smb */
4396 } else {
4397 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4398 response_data =
4399 (FILE_SYSTEM_UNIX_INFO
4400 *) (((char *) &pSMBr->hdr.Protocol) +
4401 data_offset);
4402 memcpy(&tcon->fsUnixInfo, response_data,
4403 sizeof (FILE_SYSTEM_UNIX_INFO));
4404 }
4405 }
4406 cifs_buf_release(pSMB);
4407
4408 if (rc == -EAGAIN)
4409 goto QFSUnixRetry;
4410
4411
4412 return rc;
4413}
4414
4415int
4416CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
4417{
4418/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4419 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4420 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4421 int rc = 0;
4422 int bytes_returned = 0;
4423 __u16 params, param_offset, offset, byte_count;
4424
4425 cFYI(1, ("In SETFSUnixInfo"));
4426SETFSUnixRetry:
4427 /* BB switch to small buf init to save memory */
4428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4429 (void **) &pSMBr);
4430 if (rc)
4431 return rc;
4432
4433 params = 4; /* 2 bytes zero followed by info level. */
4434 pSMB->MaxSetupCount = 0;
4435 pSMB->Reserved = 0;
4436 pSMB->Flags = 0;
4437 pSMB->Timeout = 0;
4438 pSMB->Reserved2 = 0;
4439 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4440 - 4;
4441 offset = param_offset + params;
4442
4443 pSMB->MaxParameterCount = cpu_to_le16(4);
4444 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4445 pSMB->SetupCount = 1;
4446 pSMB->Reserved3 = 0;
4447 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4448 byte_count = 1 /* pad */ + params + 12;
4449
4450 pSMB->DataCount = cpu_to_le16(12);
4451 pSMB->ParameterCount = cpu_to_le16(params);
4452 pSMB->TotalDataCount = pSMB->DataCount;
4453 pSMB->TotalParameterCount = pSMB->ParameterCount;
4454 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4455 pSMB->DataOffset = cpu_to_le16(offset);
4456
4457 /* Params. */
4458 pSMB->FileNum = 0;
4459 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4460
4461 /* Data. */
4462 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4463 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4464 pSMB->ClientUnixCap = cpu_to_le64(cap);
4465
4466 pSMB->hdr.smb_buf_length += byte_count;
4467 pSMB->ByteCount = cpu_to_le16(byte_count);
4468
4469 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4470 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4471 if (rc) {
4472 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4473 } else { /* decode response */
4474 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4475 if (rc) {
4476 rc = -EIO; /* bad smb */
4477 }
4478 }
4479 cifs_buf_release(pSMB);
4480
4481 if (rc == -EAGAIN)
4482 goto SETFSUnixRetry;
4483
4484 return rc;
4485}
4486
4487
4488
4489int
4490CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
4491 struct kstatfs *FSData)
4492{
4493/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4494 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4495 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4496 FILE_SYSTEM_POSIX_INFO *response_data;
4497 int rc = 0;
4498 int bytes_returned = 0;
4499 __u16 params, byte_count;
4500
4501 cFYI(1, ("In QFSPosixInfo"));
4502QFSPosixRetry:
4503 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4504 (void **) &pSMBr);
4505 if (rc)
4506 return rc;
4507
4508 params = 2; /* level */
4509 pSMB->TotalDataCount = 0;
4510 pSMB->DataCount = 0;
4511 pSMB->DataOffset = 0;
4512 pSMB->MaxParameterCount = cpu_to_le16(2);
4513 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4514 pSMB->MaxSetupCount = 0;
4515 pSMB->Reserved = 0;
4516 pSMB->Flags = 0;
4517 pSMB->Timeout = 0;
4518 pSMB->Reserved2 = 0;
4519 byte_count = params + 1 /* pad */ ;
4520 pSMB->ParameterCount = cpu_to_le16(params);
4521 pSMB->TotalParameterCount = pSMB->ParameterCount;
4522 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4523 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4524 pSMB->SetupCount = 1;
4525 pSMB->Reserved3 = 0;
4526 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4527 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4528 pSMB->hdr.smb_buf_length += byte_count;
4529 pSMB->ByteCount = cpu_to_le16(byte_count);
4530
4531 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4532 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4533 if (rc) {
4534 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4535 } else { /* decode response */
4536 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4537
4538 if (rc || (pSMBr->ByteCount < 13)) {
4539 rc = -EIO; /* bad smb */
4540 } else {
4541 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4542 response_data =
4543 (FILE_SYSTEM_POSIX_INFO
4544 *) (((char *) &pSMBr->hdr.Protocol) +
4545 data_offset);
4546 FSData->f_bsize =
4547 le32_to_cpu(response_data->BlockSize);
4548 FSData->f_blocks =
4549 le64_to_cpu(response_data->TotalBlocks);
4550 FSData->f_bfree =
4551 le64_to_cpu(response_data->BlocksAvail);
4552 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
4553 FSData->f_bavail = FSData->f_bfree;
4554 } else {
4555 FSData->f_bavail =
4556 le64_to_cpu(response_data->UserBlocksAvail);
4557 }
4558 if (response_data->TotalFileNodes != cpu_to_le64(-1))
4559 FSData->f_files =
4560 le64_to_cpu(response_data->TotalFileNodes);
4561 if (response_data->FreeFileNodes != cpu_to_le64(-1))
4562 FSData->f_ffree =
4563 le64_to_cpu(response_data->FreeFileNodes);
4564 }
4565 }
4566 cifs_buf_release(pSMB);
4567
4568 if (rc == -EAGAIN)
4569 goto QFSPosixRetry;
4570
4571 return rc;
4572}
4573
4574
4575/* We can not use write of zero bytes trick to
4576 set file size due to need for large file support. Also note that
4577 this SetPathInfo is preferred to SetFileInfo based method in next
4578 routine which is only needed to work around a sharing violation bug
4579 in Samba which this routine can run into */
4580
4581int
4582CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4583 __u64 size, int SetAllocation,
4584 const struct nls_table *nls_codepage, int remap)
4585{
4586 struct smb_com_transaction2_spi_req *pSMB = NULL;
4587 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4588 struct file_end_of_file_info *parm_data;
4589 int name_len;
4590 int rc = 0;
4591 int bytes_returned = 0;
4592 __u16 params, byte_count, data_count, param_offset, offset;
4593
4594 cFYI(1, ("In SetEOF"));
4595SetEOFRetry:
4596 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4597 (void **) &pSMBr);
4598 if (rc)
4599 return rc;
4600
4601 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4602 name_len =
4603 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4604 PATH_MAX, nls_codepage, remap);
4605 name_len++; /* trailing null */
4606 name_len *= 2;
4607 } else { /* BB improve the check for buffer overruns BB */
4608 name_len = strnlen(fileName, PATH_MAX);
4609 name_len++; /* trailing null */
4610 strncpy(pSMB->FileName, fileName, name_len);
4611 }
4612 params = 6 + name_len;
4613 data_count = sizeof (struct file_end_of_file_info);
4614 pSMB->MaxParameterCount = cpu_to_le16(2);
4615 pSMB->MaxDataCount = cpu_to_le16(4100);
4616 pSMB->MaxSetupCount = 0;
4617 pSMB->Reserved = 0;
4618 pSMB->Flags = 0;
4619 pSMB->Timeout = 0;
4620 pSMB->Reserved2 = 0;
4621 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4622 InformationLevel) - 4;
4623 offset = param_offset + params;
4624 if (SetAllocation) {
4625 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4626 pSMB->InformationLevel =
4627 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4628 else
4629 pSMB->InformationLevel =
4630 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4631 } else /* Set File Size */ {
4632 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4633 pSMB->InformationLevel =
4634 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4635 else
4636 pSMB->InformationLevel =
4637 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4638 }
4639
4640 parm_data =
4641 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4642 offset);
4643 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4644 pSMB->DataOffset = cpu_to_le16(offset);
4645 pSMB->SetupCount = 1;
4646 pSMB->Reserved3 = 0;
4647 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4648 byte_count = 3 /* pad */ + params + data_count;
4649 pSMB->DataCount = cpu_to_le16(data_count);
4650 pSMB->TotalDataCount = pSMB->DataCount;
4651 pSMB->ParameterCount = cpu_to_le16(params);
4652 pSMB->TotalParameterCount = pSMB->ParameterCount;
4653 pSMB->Reserved4 = 0;
4654 pSMB->hdr.smb_buf_length += byte_count;
4655 parm_data->FileSize = cpu_to_le64(size);
4656 pSMB->ByteCount = cpu_to_le16(byte_count);
4657 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4658 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4659 if (rc) {
4660 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4661 }
4662
4663 cifs_buf_release(pSMB);
4664
4665 if (rc == -EAGAIN)
4666 goto SetEOFRetry;
4667
4668 return rc;
4669}
4670
4671int
4672CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4673 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4674{
4675 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4676 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4677 char *data_offset;
4678 struct file_end_of_file_info *parm_data;
4679 int rc = 0;
4680 int bytes_returned = 0;
4681 __u16 params, param_offset, offset, byte_count, count;
4682
4683 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4684 (long long)size));
4685 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4686
4687 if (rc)
4688 return rc;
4689
4690 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4691
4692 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4693 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4694
4695 params = 6;
4696 pSMB->MaxSetupCount = 0;
4697 pSMB->Reserved = 0;
4698 pSMB->Flags = 0;
4699 pSMB->Timeout = 0;
4700 pSMB->Reserved2 = 0;
4701 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4702 offset = param_offset + params;
4703
4704 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4705
4706 count = sizeof(struct file_end_of_file_info);
4707 pSMB->MaxParameterCount = cpu_to_le16(2);
4708 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4709 pSMB->SetupCount = 1;
4710 pSMB->Reserved3 = 0;
4711 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4712 byte_count = 3 /* pad */ + params + count;
4713 pSMB->DataCount = cpu_to_le16(count);
4714 pSMB->ParameterCount = cpu_to_le16(params);
4715 pSMB->TotalDataCount = pSMB->DataCount;
4716 pSMB->TotalParameterCount = pSMB->ParameterCount;
4717 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4718 parm_data =
4719 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4720 + offset);
4721 pSMB->DataOffset = cpu_to_le16(offset);
4722 parm_data->FileSize = cpu_to_le64(size);
4723 pSMB->Fid = fid;
4724 if (SetAllocation) {
4725 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4726 pSMB->InformationLevel =
4727 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4728 else
4729 pSMB->InformationLevel =
4730 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4731 } else /* Set File Size */ {
4732 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4733 pSMB->InformationLevel =
4734 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4735 else
4736 pSMB->InformationLevel =
4737 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4738 }
4739 pSMB->Reserved4 = 0;
4740 pSMB->hdr.smb_buf_length += byte_count;
4741 pSMB->ByteCount = cpu_to_le16(byte_count);
4742 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4743 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4744 if (rc) {
4745 cFYI(1,
4746 ("Send error in SetFileInfo (SetFileSize) = %d",
4747 rc));
4748 }
4749
4750 if (pSMB)
4751 cifs_small_buf_release(pSMB);
4752
4753 /* Note: On -EAGAIN error only caller can retry on handle based calls
4754 since file handle passed in no longer valid */
4755
4756 return rc;
4757}
4758
4759/* Some legacy servers such as NT4 require that the file times be set on
4760 an open handle, rather than by pathname - this is awkward due to
4761 potential access conflicts on the open, but it is unavoidable for these
4762 old servers since the only other choice is to go from 100 nanosecond DCE
4763 time and resort to the original setpathinfo level which takes the ancient
4764 DOS time format with 2 second granularity */
4765int
4766CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4767 const FILE_BASIC_INFO *data, __u16 fid)
4768{
4769 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4770 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4771 char *data_offset;
4772 int rc = 0;
4773 int bytes_returned = 0;
4774 __u16 params, param_offset, offset, byte_count, count;
4775
4776 cFYI(1, ("Set Times (via SetFileInfo)"));
4777 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4778
4779 if (rc)
4780 return rc;
4781
4782 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4783
4784 /* At this point there is no need to override the current pid
4785 with the pid of the opener, but that could change if we someday
4786 use an existing handle (rather than opening one on the fly) */
4787 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4788 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4789
4790 params = 6;
4791 pSMB->MaxSetupCount = 0;
4792 pSMB->Reserved = 0;
4793 pSMB->Flags = 0;
4794 pSMB->Timeout = 0;
4795 pSMB->Reserved2 = 0;
4796 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4797 offset = param_offset + params;
4798
4799 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4800
4801 count = sizeof (FILE_BASIC_INFO);
4802 pSMB->MaxParameterCount = cpu_to_le16(2);
4803 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4804 pSMB->SetupCount = 1;
4805 pSMB->Reserved3 = 0;
4806 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4807 byte_count = 3 /* pad */ + params + count;
4808 pSMB->DataCount = cpu_to_le16(count);
4809 pSMB->ParameterCount = cpu_to_le16(params);
4810 pSMB->TotalDataCount = pSMB->DataCount;
4811 pSMB->TotalParameterCount = pSMB->ParameterCount;
4812 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4813 pSMB->DataOffset = cpu_to_le16(offset);
4814 pSMB->Fid = fid;
4815 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4816 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4817 else
4818 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4819 pSMB->Reserved4 = 0;
4820 pSMB->hdr.smb_buf_length += byte_count;
4821 pSMB->ByteCount = cpu_to_le16(byte_count);
4822 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
4823 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4824 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4825 if (rc) {
4826 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
4827 }
4828
4829 cifs_small_buf_release(pSMB);
4830
4831 /* Note: On -EAGAIN error only caller can retry on handle based calls
4832 since file handle passed in no longer valid */
4833
4834 return rc;
4835}
4836
4837
4838int
4839CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4840 const FILE_BASIC_INFO *data,
4841 const struct nls_table *nls_codepage, int remap)
4842{
4843 TRANSACTION2_SPI_REQ *pSMB = NULL;
4844 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4845 int name_len;
4846 int rc = 0;
4847 int bytes_returned = 0;
4848 char *data_offset;
4849 __u16 params, param_offset, offset, byte_count, count;
4850
4851 cFYI(1, ("In SetTimes"));
4852
4853SetTimesRetry:
4854 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4855 (void **) &pSMBr);
4856 if (rc)
4857 return rc;
4858
4859 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4860 name_len =
4861 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4862 PATH_MAX, nls_codepage, remap);
4863 name_len++; /* trailing null */
4864 name_len *= 2;
4865 } else { /* BB improve the check for buffer overruns BB */
4866 name_len = strnlen(fileName, PATH_MAX);
4867 name_len++; /* trailing null */
4868 strncpy(pSMB->FileName, fileName, name_len);
4869 }
4870
4871 params = 6 + name_len;
4872 count = sizeof (FILE_BASIC_INFO);
4873 pSMB->MaxParameterCount = cpu_to_le16(2);
4874 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4875 pSMB->MaxSetupCount = 0;
4876 pSMB->Reserved = 0;
4877 pSMB->Flags = 0;
4878 pSMB->Timeout = 0;
4879 pSMB->Reserved2 = 0;
4880 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4881 InformationLevel) - 4;
4882 offset = param_offset + params;
4883 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4884 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4885 pSMB->DataOffset = cpu_to_le16(offset);
4886 pSMB->SetupCount = 1;
4887 pSMB->Reserved3 = 0;
4888 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4889 byte_count = 3 /* pad */ + params + count;
4890
4891 pSMB->DataCount = cpu_to_le16(count);
4892 pSMB->ParameterCount = cpu_to_le16(params);
4893 pSMB->TotalDataCount = pSMB->DataCount;
4894 pSMB->TotalParameterCount = pSMB->ParameterCount;
4895 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4896 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4897 else
4898 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4899 pSMB->Reserved4 = 0;
4900 pSMB->hdr.smb_buf_length += byte_count;
4901 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4902 pSMB->ByteCount = cpu_to_le16(byte_count);
4903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4905 if (rc) {
4906 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4907 }
4908
4909 cifs_buf_release(pSMB);
4910
4911 if (rc == -EAGAIN)
4912 goto SetTimesRetry;
4913
4914 return rc;
4915}
4916
4917/* Can not be used to set time stamps yet (due to old DOS time format) */
4918/* Can be used to set attributes */
4919#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4920 handling it anyway and NT4 was what we thought it would be needed for
4921 Do not delete it until we prove whether needed for Win9x though */
4922int
4923CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4924 __u16 dos_attrs, const struct nls_table *nls_codepage)
4925{
4926 SETATTR_REQ *pSMB = NULL;
4927 SETATTR_RSP *pSMBr = NULL;
4928 int rc = 0;
4929 int bytes_returned;
4930 int name_len;
4931
4932 cFYI(1, ("In SetAttrLegacy"));
4933
4934SetAttrLgcyRetry:
4935 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4936 (void **) &pSMBr);
4937 if (rc)
4938 return rc;
4939
4940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4941 name_len =
4942 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
4943 PATH_MAX, nls_codepage);
4944 name_len++; /* trailing null */
4945 name_len *= 2;
4946 } else { /* BB improve the check for buffer overruns BB */
4947 name_len = strnlen(fileName, PATH_MAX);
4948 name_len++; /* trailing null */
4949 strncpy(pSMB->fileName, fileName, name_len);
4950 }
4951 pSMB->attr = cpu_to_le16(dos_attrs);
4952 pSMB->BufferFormat = 0x04;
4953 pSMB->hdr.smb_buf_length += name_len + 1;
4954 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4955 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4956 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4957 if (rc) {
4958 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4959 }
4960
4961 cifs_buf_release(pSMB);
4962
4963 if (rc == -EAGAIN)
4964 goto SetAttrLgcyRetry;
4965
4966 return rc;
4967}
4968#endif /* temporarily unneeded SetAttr legacy function */
4969
4970int
4971CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4972 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4973 dev_t device, const struct nls_table *nls_codepage,
4974 int remap)
4975{
4976 TRANSACTION2_SPI_REQ *pSMB = NULL;
4977 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4978 int name_len;
4979 int rc = 0;
4980 int bytes_returned = 0;
4981 FILE_UNIX_BASIC_INFO *data_offset;
4982 __u16 params, param_offset, offset, count, byte_count;
4983
4984 cFYI(1, ("In SetUID/GID/Mode"));
4985setPermsRetry:
4986 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4987 (void **) &pSMBr);
4988 if (rc)
4989 return rc;
4990
4991 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4992 name_len =
4993 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4994 PATH_MAX, nls_codepage, remap);
4995 name_len++; /* trailing null */
4996 name_len *= 2;
4997 } else { /* BB improve the check for buffer overruns BB */
4998 name_len = strnlen(fileName, PATH_MAX);
4999 name_len++; /* trailing null */
5000 strncpy(pSMB->FileName, fileName, name_len);
5001 }
5002
5003 params = 6 + name_len;
5004 count = sizeof (FILE_UNIX_BASIC_INFO);
5005 pSMB->MaxParameterCount = cpu_to_le16(2);
5006 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5007 pSMB->MaxSetupCount = 0;
5008 pSMB->Reserved = 0;
5009 pSMB->Flags = 0;
5010 pSMB->Timeout = 0;
5011 pSMB->Reserved2 = 0;
5012 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5013 InformationLevel) - 4;
5014 offset = param_offset + params;
5015 data_offset =
5016 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5017 offset);
5018 memset(data_offset, 0, count);
5019 pSMB->DataOffset = cpu_to_le16(offset);
5020 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5021 pSMB->SetupCount = 1;
5022 pSMB->Reserved3 = 0;
5023 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5024 byte_count = 3 /* pad */ + params + count;
5025 pSMB->ParameterCount = cpu_to_le16(params);
5026 pSMB->DataCount = cpu_to_le16(count);
5027 pSMB->TotalParameterCount = pSMB->ParameterCount;
5028 pSMB->TotalDataCount = pSMB->DataCount;
5029 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5030 pSMB->Reserved4 = 0;
5031 pSMB->hdr.smb_buf_length += byte_count;
5032 /* Samba server ignores set of file size to zero due to bugs in some
5033 older clients, but we should be precise - we use SetFileSize to
5034 set file size and do not want to truncate file size to zero
5035 accidently as happened on one Samba server beta by putting
5036 zero instead of -1 here */
5037 data_offset->EndOfFile = NO_CHANGE_64;
5038 data_offset->NumOfBytes = NO_CHANGE_64;
5039 data_offset->LastStatusChange = NO_CHANGE_64;
5040 data_offset->LastAccessTime = NO_CHANGE_64;
5041 data_offset->LastModificationTime = NO_CHANGE_64;
5042 data_offset->Uid = cpu_to_le64(uid);
5043 data_offset->Gid = cpu_to_le64(gid);
5044 /* better to leave device as zero when it is */
5045 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5046 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5047 data_offset->Permissions = cpu_to_le64(mode);
5048
5049 if (S_ISREG(mode))
5050 data_offset->Type = cpu_to_le32(UNIX_FILE);
5051 else if (S_ISDIR(mode))
5052 data_offset->Type = cpu_to_le32(UNIX_DIR);
5053 else if (S_ISLNK(mode))
5054 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5055 else if (S_ISCHR(mode))
5056 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5057 else if (S_ISBLK(mode))
5058 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5059 else if (S_ISFIFO(mode))
5060 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5061 else if (S_ISSOCK(mode))
5062 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5063
5064
5065 pSMB->ByteCount = cpu_to_le16(byte_count);
5066 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5067 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5068 if (rc) {
5069 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5070 }
5071
5072 if (pSMB)
5073 cifs_buf_release(pSMB);
5074 if (rc == -EAGAIN)
5075 goto setPermsRetry;
5076 return rc;
5077}
5078
5079int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5080 const int notify_subdirs, const __u16 netfid,
5081 __u32 filter, struct file *pfile, int multishot,
5082 const struct nls_table *nls_codepage)
5083{
5084 int rc = 0;
5085 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5086 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5087 struct dir_notify_req *dnotify_req;
5088 int bytes_returned;
5089
5090 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
5091 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5092 (void **) &pSMBr);
5093 if (rc)
5094 return rc;
5095
5096 pSMB->TotalParameterCount = 0 ;
5097 pSMB->TotalDataCount = 0;
5098 pSMB->MaxParameterCount = cpu_to_le32(2);
5099 /* BB find exact data count max from sess structure BB */
5100 pSMB->MaxDataCount = 0; /* same in little endian or be */
5101/* BB VERIFY verify which is correct for above BB */
5102 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5103 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5104
5105 pSMB->MaxSetupCount = 4;
5106 pSMB->Reserved = 0;
5107 pSMB->ParameterOffset = 0;
5108 pSMB->DataCount = 0;
5109 pSMB->DataOffset = 0;
5110 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5111 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5112 pSMB->ParameterCount = pSMB->TotalParameterCount;
5113 if (notify_subdirs)
5114 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5115 pSMB->Reserved2 = 0;
5116 pSMB->CompletionFilter = cpu_to_le32(filter);
5117 pSMB->Fid = netfid; /* file handle always le */
5118 pSMB->ByteCount = 0;
5119
5120 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5121 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5122 if (rc) {
5123 cFYI(1, ("Error in Notify = %d", rc));
5124 } else {
5125 /* Add file to outstanding requests */
5126 /* BB change to kmem cache alloc */
5127 dnotify_req = kmalloc(
5128 sizeof(struct dir_notify_req),
5129 GFP_KERNEL);
5130 if (dnotify_req) {
5131 dnotify_req->Pid = pSMB->hdr.Pid;
5132 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5133 dnotify_req->Mid = pSMB->hdr.Mid;
5134 dnotify_req->Tid = pSMB->hdr.Tid;
5135 dnotify_req->Uid = pSMB->hdr.Uid;
5136 dnotify_req->netfid = netfid;
5137 dnotify_req->pfile = pfile;
5138 dnotify_req->filter = filter;
5139 dnotify_req->multishot = multishot;
5140 spin_lock(&GlobalMid_Lock);
5141 list_add_tail(&dnotify_req->lhead,
5142 &GlobalDnotifyReqList);
5143 spin_unlock(&GlobalMid_Lock);
5144 } else
5145 rc = -ENOMEM;
5146 }
5147 cifs_buf_release(pSMB);
5148 return rc;
5149}
5150#ifdef CONFIG_CIFS_XATTR
5151ssize_t
5152CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5153 const unsigned char *searchName,
5154 char *EAData, size_t buf_size,
5155 const struct nls_table *nls_codepage, int remap)
5156{
5157 /* BB assumes one setup word */
5158 TRANSACTION2_QPI_REQ *pSMB = NULL;
5159 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5160 int rc = 0;
5161 int bytes_returned;
5162 int name_len;
5163 struct fea *temp_fea;
5164 char *temp_ptr;
5165 __u16 params, byte_count;
5166
5167 cFYI(1, ("In Query All EAs path %s", searchName));
5168QAllEAsRetry:
5169 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5170 (void **) &pSMBr);
5171 if (rc)
5172 return rc;
5173
5174 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5175 name_len =
5176 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5177 PATH_MAX, nls_codepage, remap);
5178 name_len++; /* trailing null */
5179 name_len *= 2;
5180 } else { /* BB improve the check for buffer overruns BB */
5181 name_len = strnlen(searchName, PATH_MAX);
5182 name_len++; /* trailing null */
5183 strncpy(pSMB->FileName, searchName, name_len);
5184 }
5185
5186 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5187 pSMB->TotalDataCount = 0;
5188 pSMB->MaxParameterCount = cpu_to_le16(2);
5189 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5190 pSMB->MaxSetupCount = 0;
5191 pSMB->Reserved = 0;
5192 pSMB->Flags = 0;
5193 pSMB->Timeout = 0;
5194 pSMB->Reserved2 = 0;
5195 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5196 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5197 pSMB->DataCount = 0;
5198 pSMB->DataOffset = 0;
5199 pSMB->SetupCount = 1;
5200 pSMB->Reserved3 = 0;
5201 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5202 byte_count = params + 1 /* pad */ ;
5203 pSMB->TotalParameterCount = cpu_to_le16(params);
5204 pSMB->ParameterCount = pSMB->TotalParameterCount;
5205 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5206 pSMB->Reserved4 = 0;
5207 pSMB->hdr.smb_buf_length += byte_count;
5208 pSMB->ByteCount = cpu_to_le16(byte_count);
5209
5210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5212 if (rc) {
5213 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5214 } else { /* decode response */
5215 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5216
5217 /* BB also check enough total bytes returned */
5218 /* BB we need to improve the validity checking
5219 of these trans2 responses */
5220 if (rc || (pSMBr->ByteCount < 4))
5221 rc = -EIO; /* bad smb */
5222 /* else if (pFindData){
5223 memcpy((char *) pFindData,
5224 (char *) &pSMBr->hdr.Protocol +
5225 data_offset, kl);
5226 }*/ else {
5227 /* check that length of list is not more than bcc */
5228 /* check that each entry does not go beyond length
5229 of list */
5230 /* check that each element of each entry does not
5231 go beyond end of list */
5232 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5233 struct fealist *ea_response_data;
5234 rc = 0;
5235 /* validate_trans2_offsets() */
5236 /* BB check if start of smb + data_offset > &bcc+ bcc */
5237 ea_response_data = (struct fealist *)
5238 (((char *) &pSMBr->hdr.Protocol) +
5239 data_offset);
5240 name_len = le32_to_cpu(ea_response_data->list_len);
5241 cFYI(1, ("ea length %d", name_len));
5242 if (name_len <= 8) {
5243 /* returned EA size zeroed at top of function */
5244 cFYI(1, ("empty EA list returned from server"));
5245 } else {
5246 /* account for ea list len */
5247 name_len -= 4;
5248 temp_fea = ea_response_data->list;
5249 temp_ptr = (char *)temp_fea;
5250 while (name_len > 0) {
5251 __u16 value_len;
5252 name_len -= 4;
5253 temp_ptr += 4;
5254 rc += temp_fea->name_len;
5255 /* account for prefix user. and trailing null */
5256 rc = rc + 5 + 1;
5257 if (rc < (int)buf_size) {
5258 memcpy(EAData, "user.", 5);
5259 EAData += 5;
5260 memcpy(EAData, temp_ptr,
5261 temp_fea->name_len);
5262 EAData += temp_fea->name_len;
5263 /* null terminate name */
5264 *EAData = 0;
5265 EAData = EAData + 1;
5266 } else if (buf_size == 0) {
5267 /* skip copy - calc size only */
5268 } else {
5269 /* stop before overrun buffer */
5270 rc = -ERANGE;
5271 break;
5272 }
5273 name_len -= temp_fea->name_len;
5274 temp_ptr += temp_fea->name_len;
5275 /* account for trailing null */
5276 name_len--;
5277 temp_ptr++;
5278 value_len =
5279 le16_to_cpu(temp_fea->value_len);
5280 name_len -= value_len;
5281 temp_ptr += value_len;
5282 /* BB check that temp_ptr is still
5283 within the SMB BB*/
5284
5285 /* no trailing null to account for
5286 in value len */
5287 /* go on to next EA */
5288 temp_fea = (struct fea *)temp_ptr;
5289 }
5290 }
5291 }
5292 }
5293 if (pSMB)
5294 cifs_buf_release(pSMB);
5295 if (rc == -EAGAIN)
5296 goto QAllEAsRetry;
5297
5298 return (ssize_t)rc;
5299}
5300
5301ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5302 const unsigned char *searchName, const unsigned char *ea_name,
5303 unsigned char *ea_value, size_t buf_size,
5304 const struct nls_table *nls_codepage, int remap)
5305{
5306 TRANSACTION2_QPI_REQ *pSMB = NULL;
5307 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5308 int rc = 0;
5309 int bytes_returned;
5310 int name_len;
5311 struct fea *temp_fea;
5312 char *temp_ptr;
5313 __u16 params, byte_count;
5314
5315 cFYI(1, ("In Query EA path %s", searchName));
5316QEARetry:
5317 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5318 (void **) &pSMBr);
5319 if (rc)
5320 return rc;
5321
5322 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5323 name_len =
5324 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
5325 PATH_MAX, nls_codepage, remap);
5326 name_len++; /* trailing null */
5327 name_len *= 2;
5328 } else { /* BB improve the check for buffer overruns BB */
5329 name_len = strnlen(searchName, PATH_MAX);
5330 name_len++; /* trailing null */
5331 strncpy(pSMB->FileName, searchName, name_len);
5332 }
5333
5334 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
5335 pSMB->TotalDataCount = 0;
5336 pSMB->MaxParameterCount = cpu_to_le16(2);
5337 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5338 pSMB->MaxSetupCount = 0;
5339 pSMB->Reserved = 0;
5340 pSMB->Flags = 0;
5341 pSMB->Timeout = 0;
5342 pSMB->Reserved2 = 0;
5343 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5344 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
5345 pSMB->DataCount = 0;
5346 pSMB->DataOffset = 0;
5347 pSMB->SetupCount = 1;
5348 pSMB->Reserved3 = 0;
5349 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5350 byte_count = params + 1 /* pad */ ;
5351 pSMB->TotalParameterCount = cpu_to_le16(params);
5352 pSMB->ParameterCount = pSMB->TotalParameterCount;
5353 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5354 pSMB->Reserved4 = 0;
5355 pSMB->hdr.smb_buf_length += byte_count;
5356 pSMB->ByteCount = cpu_to_le16(byte_count);
5357
5358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5359 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5360 if (rc) {
5361 cFYI(1, ("Send error in Query EA = %d", rc));
5362 } else { /* decode response */
5363 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5364
5365 /* BB also check enough total bytes returned */
5366 /* BB we need to improve the validity checking
5367 of these trans2 responses */
5368 if (rc || (pSMBr->ByteCount < 4))
5369 rc = -EIO; /* bad smb */
5370 /* else if (pFindData){
5371 memcpy((char *) pFindData,
5372 (char *) &pSMBr->hdr.Protocol +
5373 data_offset, kl);
5374 }*/ else {
5375 /* check that length of list is not more than bcc */
5376 /* check that each entry does not go beyond length
5377 of list */
5378 /* check that each element of each entry does not
5379 go beyond end of list */
5380 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5381 struct fealist *ea_response_data;
5382 rc = -ENODATA;
5383 /* validate_trans2_offsets() */
5384 /* BB check if start of smb + data_offset > &bcc+ bcc*/
5385 ea_response_data = (struct fealist *)
5386 (((char *) &pSMBr->hdr.Protocol) +
5387 data_offset);
5388 name_len = le32_to_cpu(ea_response_data->list_len);
5389 cFYI(1, ("ea length %d", name_len));
5390 if (name_len <= 8) {
5391 /* returned EA size zeroed at top of function */
5392 cFYI(1, ("empty EA list returned from server"));
5393 } else {
5394 /* account for ea list len */
5395 name_len -= 4;
5396 temp_fea = ea_response_data->list;
5397 temp_ptr = (char *)temp_fea;
5398 /* loop through checking if we have a matching
5399 name and then return the associated value */
5400 while (name_len > 0) {
5401 __u16 value_len;
5402 name_len -= 4;
5403 temp_ptr += 4;
5404 value_len =
5405 le16_to_cpu(temp_fea->value_len);
5406 /* BB validate that value_len falls within SMB,
5407 even though maximum for name_len is 255 */
5408 if (memcmp(temp_fea->name, ea_name,
5409 temp_fea->name_len) == 0) {
5410 /* found a match */
5411 rc = value_len;
5412 /* account for prefix user. and trailing null */
5413 if (rc <= (int)buf_size) {
5414 memcpy(ea_value,
5415 temp_fea->name+temp_fea->name_len+1,
5416 rc);
5417 /* ea values, unlike ea
5418 names, are not null
5419 terminated */
5420 } else if (buf_size == 0) {
5421 /* skip copy - calc size only */
5422 } else {
5423 /* stop before overrun buffer */
5424 rc = -ERANGE;
5425 }
5426 break;
5427 }
5428 name_len -= temp_fea->name_len;
5429 temp_ptr += temp_fea->name_len;
5430 /* account for trailing null */
5431 name_len--;
5432 temp_ptr++;
5433 name_len -= value_len;
5434 temp_ptr += value_len;
5435 /* No trailing null to account for in
5436 value_len. Go on to next EA */
5437 temp_fea = (struct fea *)temp_ptr;
5438 }
5439 }
5440 }
5441 }
5442 if (pSMB)
5443 cifs_buf_release(pSMB);
5444 if (rc == -EAGAIN)
5445 goto QEARetry;
5446
5447 return (ssize_t)rc;
5448}
5449
5450int
5451CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5452 const char *ea_name, const void *ea_value,
5453 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5454 int remap)
5455{
5456 struct smb_com_transaction2_spi_req *pSMB = NULL;
5457 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5458 struct fealist *parm_data;
5459 int name_len;
5460 int rc = 0;
5461 int bytes_returned = 0;
5462 __u16 params, param_offset, byte_count, offset, count;
5463
5464 cFYI(1, ("In SetEA"));
5465SetEARetry:
5466 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5467 (void **) &pSMBr);
5468 if (rc)
5469 return rc;
5470
5471 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5472 name_len =
5473 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
5474 PATH_MAX, nls_codepage, remap);
5475 name_len++; /* trailing null */
5476 name_len *= 2;
5477 } else { /* BB improve the check for buffer overruns BB */
5478 name_len = strnlen(fileName, PATH_MAX);
5479 name_len++; /* trailing null */
5480 strncpy(pSMB->FileName, fileName, name_len);
5481 }
5482
5483 params = 6 + name_len;
5484
5485 /* done calculating parms using name_len of file name,
5486 now use name_len to calculate length of ea name
5487 we are going to create in the inode xattrs */
5488 if (ea_name == NULL)
5489 name_len = 0;
5490 else
5491 name_len = strnlen(ea_name, 255);
5492
5493 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5494 pSMB->MaxParameterCount = cpu_to_le16(2);
5495 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5496 pSMB->MaxSetupCount = 0;
5497 pSMB->Reserved = 0;
5498 pSMB->Flags = 0;
5499 pSMB->Timeout = 0;
5500 pSMB->Reserved2 = 0;
5501 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5502 InformationLevel) - 4;
5503 offset = param_offset + params;
5504 pSMB->InformationLevel =
5505 cpu_to_le16(SMB_SET_FILE_EA);
5506
5507 parm_data =
5508 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5509 offset);
5510 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5511 pSMB->DataOffset = cpu_to_le16(offset);
5512 pSMB->SetupCount = 1;
5513 pSMB->Reserved3 = 0;
5514 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5515 byte_count = 3 /* pad */ + params + count;
5516 pSMB->DataCount = cpu_to_le16(count);
5517 parm_data->list_len = cpu_to_le32(count);
5518 parm_data->list[0].EA_flags = 0;
5519 /* we checked above that name len is less than 255 */
5520 parm_data->list[0].name_len = (__u8)name_len;
5521 /* EA names are always ASCII */
5522 if (ea_name)
5523 strncpy(parm_data->list[0].name, ea_name, name_len);
5524 parm_data->list[0].name[name_len] = 0;
5525 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5526 /* caller ensures that ea_value_len is less than 64K but
5527 we need to ensure that it fits within the smb */
5528
5529 /*BB add length check to see if it would fit in
5530 negotiated SMB buffer size BB */
5531 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5532 if (ea_value_len)
5533 memcpy(parm_data->list[0].name+name_len+1,
5534 ea_value, ea_value_len);
5535
5536 pSMB->TotalDataCount = pSMB->DataCount;
5537 pSMB->ParameterCount = cpu_to_le16(params);
5538 pSMB->TotalParameterCount = pSMB->ParameterCount;
5539 pSMB->Reserved4 = 0;
5540 pSMB->hdr.smb_buf_length += byte_count;
5541 pSMB->ByteCount = cpu_to_le16(byte_count);
5542 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5543 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5544 if (rc) {
5545 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5546 }
5547
5548 cifs_buf_release(pSMB);
5549
5550 if (rc == -EAGAIN)
5551 goto SetEARetry;
5552
5553 return rc;
5554}
5555
5556#endif