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