ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2003
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   Contains the routines for constructing the SMB PDUs themselves
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
25  /* These are mostly routines that operate on a pathname, or on a tree id     */
26  /* (mounted volume), but there are eight handle based routines which must be */
27  /* treated slightly different for reconnection purposes since we never want  */
28  /* to reuse a stale file handle and the caller knows the file handle */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <asm/uaccess.h>
34 #include "cifspdu.h"
35 #include "cifsglob.h"
36 #include "cifsproto.h"
37 #include "cifs_unicode.h"
38 #include "cifs_debug.h"
39
40 static struct {
41         int index;
42         char *name;
43 } protocols[] = {
44         {CIFS_PROT, "\2NT LM 0.12"}, 
45         {BAD_PROT, "\2"}
46 };
47
48
49 /* Mark as invalid, all open files on tree connections since they
50    were closed when session to server was lost */
51 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
52 {
53         struct cifsFileInfo *open_file = NULL;
54         struct list_head * tmp;
55         struct list_head * tmp1;
56
57 /* list all files open on tree connection and mark them invalid */
58         write_lock(&GlobalSMBSeslock);
59         list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
60                 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
61                 if(open_file) {
62                         open_file->invalidHandle = TRUE;
63                 }
64         }
65         write_unlock(&GlobalSMBSeslock);
66         /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */
67 }
68
69 static int
70 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
71          void **request_buf /* returned */ ,
72          void **response_buf /* returned */ )
73 {
74         int rc = 0;
75
76         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
77            check for tcp and smb session status done differently
78            for those three - in the calling routine */
79         if(tcon) {
80                 if((tcon->ses) && (tcon->ses->server)){
81                         struct nls_table *nls_codepage;
82                                 /* Give Demultiplex thread up to 10 seconds to 
83                                         reconnect, should be greater than cifs socket
84                                         timeout which is 7 seconds */
85                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
86                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
87                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
88                                 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
89                                         /* on "soft" mounts we wait once */
90                                         if((tcon->retry == FALSE) || 
91                                            (tcon->ses->status == CifsExiting)) {
92                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
93                                                 return -EHOSTDOWN;
94                                         } /* else "hard" mount - keep retrying until 
95                                         process is killed or server comes back up */
96                                 } else /* TCP session is reestablished now */
97                                         break;
98                                  
99                         }
100                         
101                         nls_codepage = load_nls_default();
102                 /* need to prevent multiple threads trying to
103                 simultaneously reconnect the same SMB session */
104                         down(&tcon->ses->sesSem);
105                         if(tcon->ses->status == CifsNeedReconnect)
106                                 rc = cifs_setup_session(0, tcon->ses, nls_codepage);
107                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
108                                 mark_open_files_invalid(tcon);
109                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
110                                         nls_codepage);
111                                 up(&tcon->ses->sesSem);
112                                 if(rc == 0)
113                                         atomic_inc(&tconInfoReconnectCount);
114
115                                 cFYI(1, ("reconnect tcon rc = %d", rc));
116                                 /* Removed call to reopen open files here - 
117                                         it is safer (and faster) to reopen files
118                                         one at a time as needed in read and write */
119
120                                 /* Check if handle based operation so we 
121                                         know whether we can continue or not without
122                                         returning to caller to reset file handle */
123                                 switch(smb_command) {
124                                         case SMB_COM_READ_ANDX:
125                                         case SMB_COM_WRITE_ANDX:
126                                         case SMB_COM_CLOSE:
127                                         case SMB_COM_FIND_CLOSE2:
128                                         case SMB_COM_LOCKING_ANDX: {
129                                                 unload_nls(nls_codepage);
130                                                 return -EAGAIN;
131                                         }
132                                 }
133                         } else {
134                                 up(&tcon->ses->sesSem);
135                         }
136                         unload_nls(nls_codepage);
137
138                 } else {
139                         return -EIO;
140                 }
141         }
142         if(rc)
143                 return rc;
144
145         *request_buf = cifs_buf_get();
146         if (request_buf == 0) {
147                 return -ENOMEM;
148         }
149     /* Although the original thought was we needed the response buf for  */
150     /* potential retries of smb operations it turns out we can determine */
151     /* from the mid flags when the request buffer can be resent without  */
152     /* having to use a second distinct buffer for the response */
153         *response_buf = *request_buf; 
154
155         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
156                         wct /*wct */ );
157         return rc;
158 }
159
160 int
161 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
162 {
163         NEGOTIATE_REQ *pSMB;
164         NEGOTIATE_RSP *pSMBr;
165         int rc = 0;
166         int bytes_returned;
167         struct TCP_Server_Info * server;
168
169         if(ses->server)
170                 server = ses->server;
171         else {
172                 rc = -EIO;
173                 return rc;
174         }
175         rc = smb_init(SMB_COM_NEGOTIATE, 0, 0 /* no tcon yet */ ,
176                       (void **) &pSMB, (void **) &pSMBr);
177         if (rc)
178                 return rc;
179
180         pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
181         if (extended_security)
182                 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
183
184         pSMB->ByteCount = strlen(protocols[0].name) + 1;
185         strncpy(pSMB->DialectsArray, protocols[0].name, 30);    
186     /* null guaranteed to be at end of source and target buffers anyway */
187
188         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
189         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
190
191         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
192                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
193         if (rc == 0) {
194                 server->secMode = pSMBr->SecurityMode;  
195                 server->secType = NTLM; /* BB override default for NTLMv2 or krb*/
196                 /* one byte - no need to convert this or EncryptionKeyLen from le,*/
197                 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
198                 /* probably no need to store and check maxvcs */
199                 server->maxBuf =
200                         min(le32_to_cpu(pSMBr->MaxBufferSize),
201                         (__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE);
202                 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
203                 cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
204                 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
205                 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
206                 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
207         /* BB with UTC do we ever need to be using srvr timezone? */
208                 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
209                         memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
210                                CIFS_CRYPTO_KEY_SIZE);
211                 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
212                            && (pSMBr->EncryptionKeyLength == 0)) {
213                         /* decode security blob */
214                 } else
215                         rc = -EIO;
216
217                 /* BB might be helpful to save off the domain of server here */
218
219                 if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) {
220                         if (pSMBr->ByteCount < 16)
221                                 rc = -EIO;
222                         else if (pSMBr->ByteCount == 16) {
223                                 server->secType = RawNTLMSSP;
224                                 if (server->socketUseCount.counter > 1) {
225                                         if (memcmp
226                                                 (server->server_GUID,
227                                                 pSMBr->u.extended_response.
228                                                 GUID, 16) != 0) {
229                                                 cFYI(1,
230                                                         ("UID of server does not match previous connection to same ip address"));
231                                                 memcpy(server->
232                                                         server_GUID,
233                                                         pSMBr->u.
234                                                         extended_response.
235                                                         GUID, 16);
236                                         }
237                                 } else
238                                         memcpy(server->server_GUID,
239                                                pSMBr->u.extended_response.
240                                                GUID, 16);
241                         } else {
242                                 rc = decode_negTokenInit(pSMBr->u.
243                                                          extended_response.
244                                                          SecurityBlob,
245                                                          pSMBr->ByteCount -
246                                                          16, &server->secType);
247                         }
248                 } else
249                         server->capabilities &= ~CAP_EXTENDED_SECURITY;
250                 if(sign_CIFS_PDUs == FALSE) {        
251                         if(server->secMode & SECMODE_SIGN_REQUIRED)
252                                 cERROR(1,
253                                  ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
254                         server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
255                 } else if(sign_CIFS_PDUs == 1) {
256                         if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
257                                 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
258                 }
259                                 
260         }
261         if (pSMB)
262                 cifs_buf_release(pSMB);
263         return rc;
264 }
265
266 int
267 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
268 {
269         struct smb_hdr *smb_buffer;
270         struct smb_hdr *smb_buffer_response;
271         int rc = 0;
272         int length;
273
274         cFYI(1, ("In tree disconnect"));
275         /*
276          *  If last user of the connection and
277          *  connection alive - disconnect it
278          *  If this is the last connection on the server session disconnect it
279          *  (and inside session disconnect we should check if tcp socket needs 
280          *  to be freed and kernel thread woken up).
281          */
282         if (tcon)
283                 down(&tcon->tconSem);
284         else
285                 return -EIO;
286
287         atomic_dec(&tcon->useCount);
288         if (atomic_read(&tcon->useCount) > 0) {
289                 up(&tcon->tconSem);
290                 return -EBUSY;
291         }
292
293         /* No need to return error on this operation if tid invalidated and 
294         closed on server already e.g. due to tcp session crashing */
295         if(tcon->tidStatus == CifsNeedReconnect) {
296                 up(&tcon->tconSem);
297                 return 0;  
298         }
299
300 /* BB remove (from server) list of shares - but with smp safety  BB */
301 /* BB is ses active - do we need to check here - but how? BB */
302         if((tcon->ses == 0) || (tcon->ses->server == 0)) {    
303                 up(&tcon->tconSem);
304                 return -EIO;
305         }
306
307         rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
308                       (void **) &smb_buffer, (void **) &smb_buffer_response);
309         if (rc) {
310                 up(&tcon->tconSem);
311                 return rc;
312         }
313         rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
314                          &length, 0);
315         if (rc)
316                 cFYI(1, (" Tree disconnect failed %d", rc));
317
318         if (smb_buffer)
319                 cifs_buf_release(smb_buffer);
320         up(&tcon->tconSem);
321
322         /* No need to return error on this operation if tid invalidated and 
323         closed on server already e.g. due to tcp session crashing */
324         if (rc == -EAGAIN)
325                 rc = 0;
326
327         return rc;
328 }
329
330 int
331 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
332 {
333         struct smb_hdr *smb_buffer_response;
334         LOGOFF_ANDX_REQ *pSMB;
335         int rc = 0;
336         int length;
337
338         cFYI(1, ("In SMBLogoff for session disconnect"));
339         if (ses)
340                 down(&ses->sesSem);
341         else
342                 return -EIO;
343
344         atomic_dec(&ses->inUse);
345         if (atomic_read(&ses->inUse) > 0) {
346                 up(&ses->sesSem);
347                 return -EBUSY;
348         }
349
350         rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, 0 /* no tcon anymore */,
351                  (void **) &pSMB, (void **) &smb_buffer_response);
352
353         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
354                 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
355
356         if (rc) {
357                 up(&ses->sesSem);
358                 return rc;
359         }
360
361         pSMB->hdr.Uid = ses->Suid;
362
363         pSMB->AndXCommand = 0xFF;
364         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
365                          smb_buffer_response, &length, 0);
366         if (ses->server) {
367                 atomic_dec(&ses->server->socketUseCount);
368                 if (atomic_read(&ses->server->socketUseCount) == 0)
369                         ses->server->tcpStatus = CifsExiting;
370         }
371         if (pSMB)
372                 cifs_buf_release(pSMB);
373         up(&ses->sesSem);
374
375         /* if session dead then we do not need to do ulogoff,
376                 since server closed smb session, no sense reporting 
377                 error */
378         if (rc == -EAGAIN)
379                 rc = 0;
380         return rc;
381 }
382
383 int
384 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
385                const char *fileName, const struct nls_table *nls_codepage)
386 {
387         DELETE_FILE_REQ *pSMB = NULL;
388         DELETE_FILE_RSP *pSMBr = NULL;
389         int rc = 0;
390         int bytes_returned;
391         int name_len;
392
393 DelFileRetry:
394         rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
395                       (void **) &pSMBr);
396         if (rc)
397                 return rc;
398
399         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
400                 name_len =
401                     cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, 530
402                                   /* find define for this maxpathcomponent */
403                                   , nls_codepage);
404                 name_len++;     /* trailing null */
405                 name_len *= 2;
406         } else {                /* BB improve the check for buffer overruns BB */
407                 name_len = strnlen(fileName, 530);
408                 name_len++;     /* trailing null */
409                 strncpy(pSMB->fileName, fileName, name_len);
410         }
411         pSMB->SearchAttributes =
412             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
413         pSMB->ByteCount = name_len + 1;
414         pSMB->BufferFormat = 0x04;
415         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
416         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
417         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
418                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
419         if (rc) {
420                 cFYI(1, ("Error in RMFile = %d", rc));
421         }
422         if (pSMB)
423                 cifs_buf_release(pSMB);
424         if (rc == -EAGAIN)
425                 goto DelFileRetry;
426
427         return rc;
428 }
429
430 int
431 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
432              const char *dirName, const struct nls_table *nls_codepage)
433 {
434         DELETE_DIRECTORY_REQ *pSMB = NULL;
435         DELETE_DIRECTORY_RSP *pSMBr = NULL;
436         int rc = 0;
437         int bytes_returned;
438         int name_len;
439
440         cFYI(1, ("In CIFSSMBRmDir"));
441 RmDirRetry:
442         rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
443                       (void **) &pSMBr);
444         if (rc)
445                 return rc;
446
447         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
448                 name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, 530
449                                 /* find define for this maxpathcomponent */
450                                 , nls_codepage);
451                 name_len++;     /* trailing null */
452                 name_len *= 2;
453         } else {                /* BB improve the check for buffer overruns BB */
454                 name_len = strnlen(dirName, 530);
455                 name_len++;     /* trailing null */
456                 strncpy(pSMB->DirName, dirName, name_len);
457         }
458
459         pSMB->ByteCount = name_len + 1;
460         pSMB->BufferFormat = 0x04;
461         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
462         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
463         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
464                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
465         if (rc) {
466                 cFYI(1, ("Error in RMDir = %d", rc));
467         }
468         if (pSMB)
469                 cifs_buf_release(pSMB);
470         if (rc == -EAGAIN)
471                 goto RmDirRetry;
472         return rc;
473 }
474
475 int
476 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
477              const char *name, const struct nls_table *nls_codepage)
478 {
479         int rc = 0;
480         CREATE_DIRECTORY_REQ *pSMB = NULL;
481         CREATE_DIRECTORY_RSP *pSMBr = NULL;
482         int bytes_returned;
483         int name_len;
484
485         cFYI(1, ("In CIFSSMBMkDir"));
486 MkDirRetry:
487         rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
488                       (void **) &pSMBr);
489         if (rc)
490                 return rc;
491
492         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
493                 name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, 530
494                                          /* find define for this maxpathcomponent */
495                                          , nls_codepage);
496                 name_len++;     /* trailing null */
497                 name_len *= 2;
498         } else {                /* BB improve the check for buffer overruns BB */
499                 name_len = strnlen(name, 530);
500                 name_len++;     /* trailing null */
501                 strncpy(pSMB->DirName, name, name_len);
502         }
503
504         pSMB->ByteCount = name_len + 1 /* for buf format */ ;
505         pSMB->BufferFormat = 0x04;
506         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
507         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
508         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
509                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
510         if (rc) {
511                 cFYI(1, ("Error in Mkdir = %d", rc));
512         }
513         if (pSMB)
514                 cifs_buf_release(pSMB);
515         if (rc == -EAGAIN)
516                 goto MkDirRetry;
517         return rc;
518 }
519
520 int
521 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
522             const char *fileName, const int openDisposition,
523             const int access_flags, const int create_options, __u16 * netfid,
524             int *pOplock, FILE_ALL_INFO * pfile_info, 
525             const struct nls_table *nls_codepage)
526 {
527         int rc = -EACCES;
528         OPEN_REQ *pSMB = NULL;
529         OPEN_RSP *pSMBr = NULL;
530         int bytes_returned;
531         int name_len;
532
533 openRetry:
534         rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
535                       (void **) &pSMBr);
536         if (rc)
537                 return rc;
538
539         pSMB->AndXCommand = 0xFF;       /* none */
540
541         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
542                 pSMB->ByteCount = 1;    /* account for one byte pad to word boundary */
543                 name_len =
544                     cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1),
545                                   fileName, 530
546                                   /* find define for this maxpathcomponent */
547                                   , nls_codepage);
548                 name_len++;     /* trailing null */
549                 name_len *= 2;
550                 pSMB->NameLength = cpu_to_le16(name_len);
551         } else {                /* BB improve the check for buffer overruns BB */
552                 pSMB->ByteCount = 0;    /* no pad */
553                 name_len = strnlen(fileName, 530);
554                 name_len++;     /* trailing null */
555                 pSMB->NameLength = cpu_to_le16(name_len);
556                 strncpy(pSMB->fileName, fileName, name_len);
557         }
558         if (*pOplock & REQ_OPLOCK)
559                 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
560         else if (*pOplock & REQ_BATCHOPLOCK) {
561                 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
562         }
563         pSMB->DesiredAccess = cpu_to_le32(access_flags);
564         pSMB->AllocationSize = 0;
565         pSMB->FileAttributes = ATTR_NORMAL;
566         /* XP does not handle ATTR_POSIX_SEMANTICS */
567         /* but it helps speed up case sensitive checks for other
568         servers such as Samba */
569         if (tcon->ses->capabilities & CAP_UNIX)
570                 pSMB->FileAttributes |= ATTR_POSIX_SEMANTICS;
571
572         /* if ((omode & S_IWUGO) == 0)
573                 pSMB->FileAttributes |= ATTR_READONLY;*/
574         /*  Above line causes problems due to vfs splitting create into two
575                 pieces - need to set mode after file created not while it is
576                 being created */
577         pSMB->FileAttributes = cpu_to_le32(pSMB->FileAttributes);
578         pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
579         pSMB->CreateDisposition = cpu_to_le32(openDisposition);
580         pSMB->CreateOptions = cpu_to_le32(create_options);
581         pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/
582         pSMB->SecurityFlags =
583             cpu_to_le32(SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY);
584
585         pSMB->ByteCount += name_len;
586         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
587
588         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
589         /* long_op set to 1 to allow for oplock break timeouts */
590         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
591                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
592         if (rc) {
593                 cFYI(1, ("Error in Open = %d", rc));
594         } else {
595                 *pOplock = pSMBr->OplockLevel;  /* one byte no need to le_to_cpu */
596                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
597                 /* Let caller know file was created so we can set the mode. */
598                 /* Do we care about the CreateAction in any other cases? */
599                 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
600                         *pOplock |= CIFS_CREATE_ACTION; 
601                 if(pfile_info) {
602                     memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
603                         36 /* CreationTime to Attributes */);
604                     /* the file_info buf is endian converted by caller */
605                     pfile_info->AllocationSize = pSMBr->AllocationSize;
606                     pfile_info->EndOfFile = pSMBr->EndOfFile;
607                     pfile_info->NumberOfLinks = cpu_to_le32(1);
608                 }
609         }
610         if (pSMB)
611                 cifs_buf_release(pSMB);
612         if (rc == -EAGAIN)
613                 goto openRetry;
614         return rc;
615 }
616
617 /* If no buffer passed in, then caller wants to do the copy
618         as in the case of readpages so the SMB buffer must be
619         freed by the caller */
620
621 int
622 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
623             const int netfid, const unsigned int count,
624             const __u64 lseek, unsigned int *nbytes, char **buf)
625 {
626         int rc = -EACCES;
627         READ_REQ *pSMB = NULL;
628         READ_RSP *pSMBr = NULL;
629         char *pReadData = NULL;
630         int bytes_returned;
631
632         *nbytes = 0;
633         rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
634                       (void **) &pSMBr);
635         if (rc)
636                 return rc;
637
638         /* tcon and ses pointer are checked in smb_init */
639         if (tcon->ses->server == NULL)
640                 return -ECONNABORTED;
641
642         pSMB->AndXCommand = 0xFF;       /* none */
643         pSMB->Fid = netfid;
644         pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
645         pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
646         pSMB->Remaining = 0;
647         pSMB->MaxCount = cpu_to_le16(count);
648         pSMB->MaxCountHigh = 0;
649         pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
650
651         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
652                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
653         if (rc) {
654                 cERROR(1, ("Send error in read = %d", rc));
655         } else {
656                 pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength);
657                 *nbytes = pSMBr->DataLength;
658                 /*check that DataLength would not go beyond end of SMB */
659                 if ((pSMBr->DataLength > CIFS_MAX_MSGSIZE) 
660                                 || (pSMBr->DataLength > count)) {
661                         cFYI(1,("bad length %d for count %d",pSMBr->DataLength,count));
662                         rc = -EIO;
663                         *nbytes = 0;
664                 } else {
665                         pReadData =
666                             (char *) (&pSMBr->hdr.Protocol) +
667                             le16_to_cpu(pSMBr->DataOffset);
668 /*                      if(rc = copy_to_user(buf, pReadData, pSMBr->DataLength)) {
669                                 cERROR(1,("Faulting on read rc = %d",rc));
670                                 rc = -EFAULT;
671                         }*/ /* can not use copy_to_user when using page cache*/
672                         if(*buf)
673                             memcpy(*buf,pReadData,pSMBr->DataLength);
674                 }
675         }
676         if (pSMB) {
677                 if(*buf)
678                         cifs_buf_release(pSMB);
679                 else
680                         *buf = (char *)pSMB;
681         }
682
683         /* Note: On -EAGAIN error only caller can retry on handle based calls 
684                 since file handle passed in no longer valid */
685         return rc;
686 }
687
688 int
689 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
690              const int netfid, const unsigned int count,
691              const __u64 offset, unsigned int *nbytes, const char *buf,
692              const int long_op)
693 {
694         int rc = -EACCES;
695         WRITE_REQ *pSMB = NULL;
696         WRITE_RSP *pSMBr = NULL;
697         int bytes_returned;
698
699         rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
700                       (void **) &pSMBr);
701         if (rc)
702                 return rc;
703         /* tcon and ses pointer are checked in smb_init */
704         if (tcon->ses->server == NULL)
705                 return -ECONNABORTED;
706
707         pSMB->AndXCommand = 0xFF;       /* none */
708         pSMB->Fid = netfid;
709         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
710         pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
711         pSMB->Remaining = 0;
712         if (count > ((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00))
713                 pSMB->DataLengthLow =
714                     (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00;
715         else
716                 pSMB->DataLengthLow = count;
717         pSMB->DataLengthHigh = 0;
718         pSMB->DataOffset =
719             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
720
721         memcpy(pSMB->Data,buf,pSMB->DataLengthLow);
722
723         pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ;
724         pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow);
725         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
726         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
727
728         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
729                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
730         if (rc) {
731                 cERROR(1, ("Send error in write = %d", rc));
732                 *nbytes = 0;
733         } else
734                 *nbytes = le16_to_cpu(pSMBr->Count);
735
736         if (pSMB)
737                 cifs_buf_release(pSMB);
738
739         /* Note: On -EAGAIN error only caller can retry on handle based calls 
740                 since file handle passed in no longer valid */
741
742         return rc;
743 }
744
745 int
746 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
747             const __u16 smb_file_id, const __u64 len,
748             const __u64 offset, const __u32 numUnlock,
749             const __u32 numLock, const __u8 lockType, const int waitFlag)
750 {
751         int rc = 0;
752         LOCK_REQ *pSMB = NULL;
753         LOCK_RSP *pSMBr = NULL;
754         int bytes_returned;
755         int timeout = 0;
756         __u64 temp;
757
758         cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
759         rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
760                       (void **) &pSMBr);
761         if (rc)
762                 return rc;
763
764         if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
765                 timeout = -1; /* no response expected */
766                 pSMB->Timeout = 0;
767         } else if (waitFlag == TRUE) {
768                 timeout = 3;  /* blocking operation, no timeout */
769                 pSMB->Timeout = -1; /* blocking - do not time out */
770         } else {
771                 pSMB->Timeout = 0;
772         }
773
774         pSMB->NumberOfLocks = cpu_to_le32(numLock);
775         pSMB->NumberOfUnlocks = cpu_to_le32(numUnlock);
776         pSMB->LockType = lockType;
777         pSMB->AndXCommand = 0xFF;       /* none */
778         pSMB->Fid = smb_file_id; /* netfid stays le */
779
780         pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
781         temp = cpu_to_le64(len);
782         pSMB->Locks[0].LengthLow = (__u32)(len & 0xFFFFFFFF);
783         pSMB->Locks[0].LengthHigh =  (__u32)(len>>32);
784         temp = cpu_to_le64(offset);
785         pSMB->Locks[0].OffsetLow = (__u32)(offset & 0xFFFFFFFF);
786         pSMB->Locks[0].OffsetHigh = (__u32)(offset>>32);
787         pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE);
788         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
789         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
790
791         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
792                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
793
794         if (rc) {
795                 cERROR(1, ("Send error in Lock = %d", rc));
796         }
797         if (pSMB)
798                 cifs_buf_release(pSMB);
799
800         /* Note: On -EAGAIN error only caller can retry on handle based calls 
801         since file handle passed in no longer valid */
802         return rc;
803 }
804
805 int
806 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
807 {
808         int rc = 0;
809         CLOSE_REQ *pSMB = NULL;
810         CLOSE_RSP *pSMBr = NULL;
811         int bytes_returned;
812         cFYI(1, ("In CIFSSMBClose"));
813
814 /* do not retry on dead session on close */
815         rc = smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB,
816                       (void **) &pSMBr);
817         if(rc == -EAGAIN)
818                 return 0;
819         if (rc)
820                 return rc;
821
822         pSMB->FileID = (__u16) smb_file_id;
823         pSMB->LastWriteTime = 0;
824         pSMB->ByteCount = 0;
825         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
826                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
827         if (rc) {
828                 if(rc!=-EINTR) {
829                         /* EINTR is expected when user ctl-c to kill app */
830                         cERROR(1, ("Send error in Close = %d", rc));
831                 }
832         }
833         if (pSMB)
834                 cifs_buf_release(pSMB);
835
836         /* Since session is dead, file will be closed on server already */
837         if(rc == -EAGAIN)
838                 rc = 0;
839
840         return rc;
841 }
842
843 int
844 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
845               const char *fromName, const char *toName,
846               const struct nls_table *nls_codepage)
847 {
848         int rc = 0;
849         RENAME_REQ *pSMB = NULL;
850         RENAME_RSP *pSMBr = NULL;
851         int bytes_returned;
852         int name_len, name_len2;
853
854         cFYI(1, ("In CIFSSMBRename"));
855 renameRetry:
856         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
857                       (void **) &pSMBr);
858         if (rc)
859                 return rc;
860
861         pSMB->BufferFormat = 0x04;
862         pSMB->SearchAttributes =
863             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
864                         ATTR_DIRECTORY);
865
866         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
867                 name_len =
868                     cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
869                                   /* find define for this maxpathcomponent */
870                                   , nls_codepage);
871                 name_len++;     /* trailing null */
872                 name_len *= 2;
873                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
874         /* protocol requires ASCII signature byte on Unicode string */
875                 pSMB->OldFileName[name_len + 1] = 0x00;
876                 name_len2 =
877                     cifs_strtoUCS((wchar_t *) & pSMB->
878                                   OldFileName[name_len + 2], toName, 530,
879                                   nls_codepage);
880                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
881                 name_len2 *= 2; /* convert to bytes */
882         } else {                /* BB improve the check for buffer overruns BB */
883                 name_len = strnlen(fromName, 530);
884                 name_len++;     /* trailing null */
885                 strncpy(pSMB->OldFileName, fromName, name_len);
886                 name_len2 = strnlen(toName, 530);
887                 name_len2++;    /* trailing null */
888                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
889                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
890                 name_len2++;    /* trailing null */
891                 name_len2++;    /* signature byte */
892         }
893
894         pSMB->ByteCount = 1 /* 1st signature byte */  + name_len + name_len2;
895     /* we could also set search attributes but not needed */
896         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
897         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
898
899         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
900                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
901         if (rc) {
902                 cFYI(1, ("Send error in rename = %d", rc));
903         }
904         if (pSMB)
905                 cifs_buf_release(pSMB);
906
907         if (rc == -EAGAIN)
908                 goto renameRetry;
909
910         return rc;
911 }
912
913 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
914                 int netfid, char * target_name, const struct nls_table * nls_codepage) 
915 {
916         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
917         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
918         struct set_file_rename * rename_info;
919         char *data_offset;
920         char dummy_string[30];
921         int rc = 0;
922         int bytes_returned = 0;
923         int len_of_str;
924
925         cFYI(1, ("Rename to File by handle"));
926         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
927                         (void **) &pSMBr);
928         if (rc)
929                 return rc;
930
931         pSMB->ParameterCount = 6;
932         pSMB->MaxSetupCount = 0;
933         pSMB->Reserved = 0;
934         pSMB->Flags = 0;
935         pSMB->Timeout = 0;
936         pSMB->Reserved2 = 0;
937         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req,
938                                 Fid) - 4;
939         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
940
941         data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
942         rename_info = (struct set_file_rename *) data_offset;
943         pSMB->MaxParameterCount = cpu_to_le16(2);
944         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
945         pSMB->SetupCount = 1;
946         pSMB->Reserved3 = 0;
947         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
948         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount;
949         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
950         pSMB->TotalParameterCount = pSMB->ParameterCount;
951         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
952         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
953         /* construct random name ".cifs_tmp<inodenum><mid>" */
954         rename_info->overwrite = cpu_to_le32(1);
955         rename_info->root_fid  = 0;
956         /* unicode only call */
957         if(target_name == NULL) {
958                 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
959                 len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage);
960         } else {
961                 len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, 530, nls_codepage);
962         }
963         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
964         pSMB->DataCount = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
965         pSMB->ByteCount += pSMB->DataCount;
966         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
967         pSMB->TotalDataCount = pSMB->DataCount;
968         pSMB->Fid = netfid;
969         pSMB->InformationLevel =
970                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
971         pSMB->Reserved4 = 0;
972         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
973         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
974         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
975                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
976         if (rc) {
977                 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
978         }
979
980         if (pSMB)
981                 cifs_buf_release(pSMB);
982
983         /* Note: On -EAGAIN error only caller can retry on handle based calls
984                 since file handle passed in no longer valid */
985
986         return rc;
987 }
988
989
990 int
991 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
992                       const char *fromName, const char *toName,
993                       const struct nls_table *nls_codepage)
994 {
995         TRANSACTION2_SPI_REQ *pSMB = NULL;
996         TRANSACTION2_SPI_RSP *pSMBr = NULL;
997         char *data_offset;
998         int name_len;
999         int name_len_target;
1000         int rc = 0;
1001         int bytes_returned = 0;
1002
1003         cFYI(1, ("In Symlink Unix style"));
1004 createSymLinkRetry:
1005         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1006                       (void **) &pSMBr);
1007         if (rc)
1008                 return rc;
1009
1010         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1011                 name_len =
1012                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, 530
1013                                   /* find define for this maxpathcomponent */
1014                                   , nls_codepage);
1015                 name_len++;     /* trailing null */
1016                 name_len *= 2;
1017
1018         } else {                /* BB improve the check for buffer overruns BB */
1019                 name_len = strnlen(fromName, 530);
1020                 name_len++;     /* trailing null */
1021                 strncpy(pSMB->FileName, fromName, name_len);
1022         }
1023         pSMB->ParameterCount = 6 + name_len;
1024         pSMB->MaxSetupCount = 0;
1025         pSMB->Reserved = 0;
1026         pSMB->Flags = 0;
1027         pSMB->Timeout = 0;
1028         pSMB->Reserved2 = 0;
1029         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
1030                                      InformationLevel) - 4;
1031         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
1032
1033         data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
1034         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1035                 name_len_target =
1036                     cifs_strtoUCS((wchar_t *) data_offset, toName, 530
1037                                   /* find define for this maxpathcomponent */
1038                                   , nls_codepage);
1039                 name_len_target++;      /* trailing null */
1040                 name_len_target *= 2;
1041         } else {                /* BB improve the check for buffer overruns BB */
1042                 name_len_target = strnlen(toName, 530);
1043                 name_len_target++;      /* trailing null */
1044                 strncpy(data_offset, toName, name_len_target);
1045         }
1046
1047         pSMB->DataCount = name_len_target;
1048         pSMB->MaxParameterCount = cpu_to_le16(2);
1049         /* BB find exact max on data count below from sess */
1050         pSMB->MaxDataCount = cpu_to_le16(1000);
1051         pSMB->SetupCount = 1;
1052         pSMB->Reserved3 = 0;
1053         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1054         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
1055         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
1056         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
1057         pSMB->TotalDataCount = pSMB->DataCount;
1058         pSMB->TotalParameterCount = pSMB->ParameterCount;
1059         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
1060         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
1061         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1062         pSMB->Reserved4 = 0;
1063         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1064         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1065         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1066                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1067         if (rc) {
1068                 cFYI(1,
1069                      ("Send error in SetPathInfo (create symlink) = %d",
1070                       rc));
1071         }
1072
1073         if (pSMB)
1074                 cifs_buf_release(pSMB);
1075
1076         if (rc == -EAGAIN)
1077                 goto createSymLinkRetry;
1078
1079         return rc;
1080 }
1081
1082 int
1083 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1084                        const char *fromName, const char *toName,
1085                        const struct nls_table *nls_codepage)
1086 {
1087         TRANSACTION2_SPI_REQ *pSMB = NULL;
1088         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1089         char *data_offset;
1090         int name_len;
1091         int name_len_target;
1092         int rc = 0;
1093         int bytes_returned = 0;
1094
1095         cFYI(1, ("In Create Hard link Unix style"));
1096 createHardLinkRetry:
1097         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1098                       (void **) &pSMBr);
1099         if (rc)
1100                 return rc;
1101
1102         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1103                 name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, 530
1104                                          /* find define for this maxpathcomponent */
1105                                          , nls_codepage);
1106                 name_len++;     /* trailing null */
1107                 name_len *= 2;
1108
1109         } else {                /* BB improve the check for buffer overruns BB */
1110                 name_len = strnlen(toName, 530);
1111                 name_len++;     /* trailing null */
1112                 strncpy(pSMB->FileName, toName, name_len);
1113         }
1114         pSMB->ParameterCount = 6 + name_len;
1115         pSMB->MaxSetupCount = 0;
1116         pSMB->Reserved = 0;
1117         pSMB->Flags = 0;
1118         pSMB->Timeout = 0;
1119         pSMB->Reserved2 = 0;
1120         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
1121                                      InformationLevel) - 4;
1122         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
1123
1124         data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
1125         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1126                 name_len_target =
1127                     cifs_strtoUCS((wchar_t *) data_offset, fromName, 530
1128                                   /* find define for this maxpathcomponent */
1129                                   , nls_codepage);
1130                 name_len_target++;      /* trailing null */
1131                 name_len_target *= 2;
1132         } else {                /* BB improve the check for buffer overruns BB */
1133                 name_len_target = strnlen(fromName, 530);
1134                 name_len_target++;      /* trailing null */
1135                 strncpy(data_offset, fromName, name_len_target);
1136         }
1137
1138         pSMB->DataCount = name_len_target;
1139         pSMB->MaxParameterCount = cpu_to_le16(2);
1140         /* BB find exact max on data count below from sess*/
1141         pSMB->MaxDataCount = cpu_to_le16(1000);
1142         pSMB->SetupCount = 1;
1143         pSMB->Reserved3 = 0;
1144         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1145         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
1146         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
1147         pSMB->TotalParameterCount = pSMB->ParameterCount;
1148         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
1149         pSMB->TotalDataCount = pSMB->DataCount;
1150         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
1151         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
1152         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1153         pSMB->Reserved4 = 0;
1154         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1155         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1156         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1157                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1158         if (rc) {
1159                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1160         }
1161
1162         if (pSMB)
1163                 cifs_buf_release(pSMB);
1164         if (rc == -EAGAIN)
1165                 goto createHardLinkRetry;
1166
1167         return rc;
1168 }
1169
1170 int
1171 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1172                    const char *fromName, const char *toName,
1173                    const struct nls_table *nls_codepage)
1174 {
1175         int rc = 0;
1176         NT_RENAME_REQ *pSMB = NULL;
1177         RENAME_RSP *pSMBr = NULL;
1178         int bytes_returned;
1179         int name_len, name_len2;
1180
1181         cFYI(1, ("In CIFSCreateHardLink"));
1182 winCreateHardLinkRetry:
1183
1184         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1185                       (void **) &pSMBr);
1186         if (rc)
1187                 return rc;
1188
1189         pSMB->SearchAttributes =
1190             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1191                         ATTR_DIRECTORY);
1192         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1193         pSMB->ClusterCount = 0;
1194
1195         pSMB->BufferFormat = 0x04;
1196
1197         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1198                 name_len =
1199                     cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
1200                                   /* find define for this maxpathcomponent */
1201                                   , nls_codepage);
1202                 name_len++;     /* trailing null */
1203                 name_len *= 2;
1204                 pSMB->OldFileName[name_len] = 0;        /* pad */
1205                 pSMB->OldFileName[name_len + 1] = 0x04; 
1206                 name_len2 =
1207                     cifs_strtoUCS((wchar_t *) & pSMB->
1208                                   OldFileName[name_len + 2], toName, 530,
1209                                   nls_codepage);
1210                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1211                 name_len2 *= 2; /* convert to bytes */
1212         } else {                /* BB improve the check for buffer overruns BB */
1213                 name_len = strnlen(fromName, 530);
1214                 name_len++;     /* trailing null */
1215                 strncpy(pSMB->OldFileName, fromName, name_len);
1216                 name_len2 = strnlen(toName, 530);
1217                 name_len2++;    /* trailing null */
1218                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
1219                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1220                 name_len2++;    /* trailing null */
1221                 name_len2++;    /* signature byte */
1222         }
1223
1224         pSMB->ByteCount = 1 /* string type byte */  + name_len + name_len2;
1225         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1226         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1227
1228         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1229                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1230         if (rc) {
1231                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1232         }
1233         if (pSMB)
1234                 cifs_buf_release(pSMB);
1235         if (rc == -EAGAIN)
1236                 goto winCreateHardLinkRetry;
1237
1238         return rc;
1239 }
1240
1241 int
1242 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1243                         const unsigned char *searchName,
1244                         char *symlinkinfo, const int buflen,
1245                         const struct nls_table *nls_codepage)
1246 {
1247 /* SMB_QUERY_FILE_UNIX_LINK */
1248         TRANSACTION2_QPI_REQ *pSMB = NULL;
1249         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1250         int rc = 0;
1251         int bytes_returned;
1252         int name_len;
1253
1254         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1255
1256 querySymLinkRetry:
1257         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1258                       (void **) &pSMBr);
1259         if (rc)
1260                 return rc;
1261
1262         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1263                 name_len =
1264                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
1265                                   /* find define for this maxpathcomponent */
1266                                   , nls_codepage);
1267                 name_len++;     /* trailing null */
1268                 name_len *= 2;
1269         } else {                /* BB improve the check for buffer overruns BB */
1270                 name_len = strnlen(searchName, 530);
1271                 name_len++;     /* trailing null */
1272                 strncpy(pSMB->FileName, searchName, name_len);
1273         }
1274
1275         pSMB->TotalParameterCount =
1276             2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1277         pSMB->TotalDataCount = 0;
1278         pSMB->MaxParameterCount = cpu_to_le16(2);
1279         /* BB find exact max data count below from sess structure BB */
1280         pSMB->MaxDataCount = cpu_to_le16(4000);
1281         pSMB->MaxSetupCount = 0;
1282         pSMB->Reserved = 0;
1283         pSMB->Flags = 0;
1284         pSMB->Timeout = 0;
1285         pSMB->Reserved2 = 0;
1286         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1287         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1288         pSMB->DataCount = 0;
1289         pSMB->DataOffset = 0;
1290         pSMB->SetupCount = 1;
1291         pSMB->Reserved3 = 0;
1292         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1293         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1294         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
1295         pSMB->ParameterCount = pSMB->TotalParameterCount;
1296         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1297         pSMB->Reserved4 = 0;
1298         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1299         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1300
1301         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1302                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1303         if (rc) {
1304                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1305         } else {                /* decode response */
1306                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
1307                 pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
1308                 if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
1309                 /* BB also check enough total bytes returned */
1310                         rc = -EIO;      /* bad smb */
1311                 else {
1312                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1313                                 name_len = UniStrnlen((wchar_t *) ((char *)
1314                                         &pSMBr->hdr.Protocol +pSMBr->DataOffset),
1315                                         min_t(const int, buflen,pSMBr->DataCount) / 2);
1316                                 cifs_strfromUCS_le(symlinkinfo,
1317                                         (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1318                                                 pSMBr->DataOffset),
1319                                         name_len, nls_codepage);
1320                         } else {
1321                                 strncpy(symlinkinfo,
1322                                         (char *) &pSMBr->hdr.Protocol + 
1323                                                 pSMBr->DataOffset,
1324                                         min_t(const int, buflen, pSMBr->DataCount));
1325                         }
1326                         symlinkinfo[buflen] = 0;
1327         /* just in case so calling code does not go off the end of buffer */
1328                 }
1329         }
1330         if (pSMB)
1331                 cifs_buf_release(pSMB);
1332         if (rc == -EAGAIN)
1333                 goto querySymLinkRetry;
1334         return rc;
1335 }
1336
1337
1338
1339 int
1340 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1341                         const unsigned char *searchName,
1342                         char *symlinkinfo, const int buflen,__u16 fid,
1343                         const struct nls_table *nls_codepage)
1344 {
1345         int rc = 0;
1346         int bytes_returned;
1347         int name_len;
1348         struct smb_com_transaction_ioctl_req * pSMB;
1349         struct smb_com_transaction_ioctl_rsp * pSMBr;
1350
1351         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1352         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1353                       (void **) &pSMBr);
1354         if (rc)
1355                 return rc;
1356
1357         pSMB->TotalParameterCount = 0 ;
1358         pSMB->TotalDataCount = 0;
1359         pSMB->MaxParameterCount = cpu_to_le16(2);
1360         /* BB find exact data count max from sess structure BB */
1361         pSMB->MaxDataCount = cpu_to_le16(4000);
1362         pSMB->MaxSetupCount = 4;
1363         pSMB->Reserved = 0;
1364         pSMB->ParameterOffset = 0;
1365         pSMB->DataCount = 0;
1366         pSMB->DataOffset = 0;
1367         pSMB->SetupCount = 4;
1368         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1369         pSMB->ParameterCount = pSMB->TotalParameterCount;
1370         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1371         pSMB->IsFsctl = 1; /* FSCTL */
1372         pSMB->IsRootFlag = 0;
1373         pSMB->Fid = fid; /* file handle always le */
1374         pSMB->ByteCount = 0;
1375
1376         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1377                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1378         if (rc) {
1379                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1380         } else {                /* decode response */
1381                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
1382                 pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
1383                 if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
1384                 /* BB also check enough total bytes returned */
1385                         rc = -EIO;      /* bad smb */
1386                 else {
1387                         if(pSMBr->DataCount && (pSMBr->DataCount < 2048)) {
1388                 /* could also validate reparse tag && better check name length */
1389                                 struct reparse_data * reparse_buf = (struct reparse_data *)
1390                                         ((char *)&pSMBr->hdr.Protocol + pSMBr->DataOffset);
1391                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1392                                         name_len = UniStrnlen((wchar_t *)
1393                                                         (reparse_buf->LinkNamesBuf + 
1394                                                         reparse_buf->TargetNameOffset),
1395                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
1396                                         cifs_strfromUCS_le(symlinkinfo,
1397                                                 (wchar_t *) (reparse_buf->LinkNamesBuf + 
1398                                                 reparse_buf->TargetNameOffset),
1399                                                 name_len, nls_codepage);
1400                                 } else { /* ASCII names */
1401                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
1402                                                 reparse_buf->TargetNameOffset, 
1403                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
1404                                 }
1405                         } else {
1406                                 rc = -EIO;
1407                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1408                         }
1409                         symlinkinfo[buflen] = 0; /* just in case so the caller
1410                                         does not go off the end of the buffer */
1411                         cFYI(1,("readlink result - %s ",symlinkinfo));
1412                 }
1413         }
1414         if (pSMB)
1415                 cifs_buf_release(pSMB);
1416
1417         /* Note: On -EAGAIN error only caller can retry on handle based calls
1418                 since file handle passed in no longer valid */
1419
1420         return rc;
1421 }
1422
1423 int
1424 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
1425                  const unsigned char *searchName,
1426                  FILE_ALL_INFO * pFindData,
1427                  const struct nls_table *nls_codepage)
1428 {
1429 /* level 263 SMB_QUERY_FILE_ALL_INFO */
1430         TRANSACTION2_QPI_REQ *pSMB = NULL;
1431         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1432         int rc = 0;
1433         int bytes_returned;
1434         int name_len;
1435
1436         cFYI(1, ("In QPathInfo path %s", searchName));
1437 QPathInfoRetry:
1438         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1439                       (void **) &pSMBr);
1440         if (rc)
1441                 return rc;
1442
1443         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1444                 name_len =
1445                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
1446                                   /* find define for this maxpathcomponent */
1447                                   , nls_codepage);
1448                 name_len++;     /* trailing null */
1449                 name_len *= 2;
1450         } else {                /* BB improve the check for buffer overruns BB */
1451                 name_len = strnlen(searchName, 530);
1452                 name_len++;     /* trailing null */
1453                 strncpy(pSMB->FileName, searchName, name_len);
1454         }
1455
1456         pSMB->TotalParameterCount = 2 /* level */  + 4 /* reserved */  +
1457             name_len /* includes null */ ;
1458         pSMB->TotalDataCount = 0;
1459         pSMB->MaxParameterCount = cpu_to_le16(2);
1460         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
1461         pSMB->MaxSetupCount = 0;
1462         pSMB->Reserved = 0;
1463         pSMB->Flags = 0;
1464         pSMB->Timeout = 0;
1465         pSMB->Reserved2 = 0;
1466         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1467         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1468         pSMB->DataCount = 0;
1469         pSMB->DataOffset = 0;
1470         pSMB->SetupCount = 1;
1471         pSMB->Reserved3 = 0;
1472         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1473         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1474         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
1475         pSMB->ParameterCount = pSMB->TotalParameterCount;
1476         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
1477         pSMB->Reserved4 = 0;
1478         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1479         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1480
1481         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1482                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1483         if (rc) {
1484                 cFYI(1, ("Send error in QPathInfo = %d", rc));
1485         } else {                /* decode response */
1486                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
1487                 /* BB also check enough total bytes returned */
1488                 if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512)) 
1489                         rc = -EIO;      /* bad smb */
1490                 else if (pFindData){
1491                         memcpy((char *) pFindData,
1492                                (char *) &pSMBr->hdr.Protocol +
1493                                pSMBr->DataOffset, sizeof (FILE_ALL_INFO));
1494                 } else
1495                     rc = -ENOMEM;
1496         }
1497         if (pSMB)
1498                 cifs_buf_release(pSMB);
1499         if (rc == -EAGAIN)
1500                 goto QPathInfoRetry;
1501
1502         return rc;
1503 }
1504
1505 int
1506 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
1507                      const unsigned char *searchName,
1508                      FILE_UNIX_BASIC_INFO * pFindData,
1509                      const struct nls_table *nls_codepage)
1510 {
1511 /* SMB_QUERY_FILE_UNIX_BASIC */
1512         TRANSACTION2_QPI_REQ *pSMB = NULL;
1513         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1514         int rc = 0;
1515         int bytes_returned = 0;
1516         int name_len;
1517
1518         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
1519 UnixQPathInfoRetry:
1520         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1521                       (void **) &pSMBr);
1522         if (rc)
1523                 return rc;
1524
1525         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1526                 name_len =
1527                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
1528                                   /* find define for this maxpathcomponent */
1529                                   , nls_codepage);
1530                 name_len++;     /* trailing null */
1531                 name_len *= 2;
1532         } else {                /* BB improve the check for buffer overruns BB */
1533                 name_len = strnlen(searchName, 530);
1534                 name_len++;     /* trailing null */
1535                 strncpy(pSMB->FileName, searchName, name_len);
1536         }
1537
1538         pSMB->TotalParameterCount = 2 /* level */  + 4 /* reserved */  +
1539             name_len /* includes null */ ;
1540         pSMB->TotalDataCount = 0;
1541         pSMB->MaxParameterCount = cpu_to_le16(2);
1542         /* BB find exact max SMB PDU from sess structure BB */
1543         pSMB->MaxDataCount = cpu_to_le16(4000); 
1544         pSMB->MaxSetupCount = 0;
1545         pSMB->Reserved = 0;
1546         pSMB->Flags = 0;
1547         pSMB->Timeout = 0;
1548         pSMB->Reserved2 = 0;
1549         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1550         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1551         pSMB->DataCount = 0;
1552         pSMB->DataOffset = 0;
1553         pSMB->SetupCount = 1;
1554         pSMB->Reserved3 = 0;
1555         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1556         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1557         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
1558         pSMB->ParameterCount = pSMB->TotalParameterCount;
1559         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1560         pSMB->Reserved4 = 0;
1561         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1562         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1563
1564         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1565                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1566         if (rc) {
1567                 cFYI(1, ("Send error in QPathInfo = %d", rc));
1568         } else {                /* decode response */
1569                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
1570                 /* BB also check if enough total bytes returned */
1571                 if ((pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO)) || 
1572                         (pSMBr->DataOffset > 512) || 
1573                         (pSMBr->DataOffset < sizeof(struct smb_hdr))) {
1574                         cFYI(1,("UnixQPathinfo invalid data offset %d bytes returned %d",
1575                                         (int)pSMBr->DataOffset,bytes_returned));
1576                         rc = -EIO;      /* bad smb */
1577                 } else {
1578                         memcpy((char *) pFindData,
1579                                (char *) &pSMBr->hdr.Protocol +
1580                                pSMBr->DataOffset,
1581                                sizeof (FILE_UNIX_BASIC_INFO));
1582                 }
1583         }
1584         if (pSMB)
1585                 cifs_buf_release(pSMB);
1586         if (rc == -EAGAIN)
1587                 goto UnixQPathInfoRetry;
1588
1589         return rc;
1590 }
1591
1592 int
1593 CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
1594                const char *searchName, FILE_ALL_INFO * findData,
1595                const struct nls_table *nls_codepage)
1596 {
1597 /* level 257 SMB_ */
1598         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
1599         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
1600         int rc = 0;
1601         int bytes_returned;
1602         int name_len;
1603
1604         cFYI(1, ("In FindUnique"));
1605 findUniqueRetry:
1606         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1607                       (void **) &pSMBr);
1608         if (rc)
1609                 return rc;
1610
1611         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1612                 name_len =
1613                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
1614                                   /* find define for this maxpathcomponent */
1615                                   , nls_codepage);
1616                 name_len++;     /* trailing null */
1617                 name_len *= 2;
1618         } else {                /* BB improve the check for buffer overruns BB */
1619                 name_len = strnlen(searchName, 530);
1620                 name_len++;     /* trailing null */
1621                 strncpy(pSMB->FileName, searchName, name_len);
1622         }
1623
1624         pSMB->TotalParameterCount = 12 + name_len /* includes null */ ;
1625         pSMB->TotalDataCount = 0;       /* no EAs */
1626         pSMB->MaxParameterCount = cpu_to_le16(2);
1627         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
1628         pSMB->MaxSetupCount = 0;
1629         pSMB->Reserved = 0;
1630         pSMB->Flags = 0;
1631         pSMB->Timeout = 0;
1632         pSMB->Reserved2 = 0;
1633         pSMB->ParameterOffset = cpu_to_le16(
1634         offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
1635         pSMB->DataCount = 0;
1636         pSMB->DataOffset = 0;
1637         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
1638         pSMB->Reserved3 = 0;
1639         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
1640         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1641         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalDataCount);
1642         pSMB->ParameterCount = pSMB->TotalParameterCount;
1643         pSMB->SearchAttributes =
1644             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1645                         ATTR_DIRECTORY);
1646         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
1647         pSMB->SearchFlags = cpu_to_le16(1);
1648         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
1649         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
1650         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1651         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1652
1653         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1654                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1655
1656         if (rc) {
1657                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
1658         } else {                /* decode response */
1659
1660                 /* BB fill in */
1661         }
1662         if (pSMB)
1663                 cifs_buf_release(pSMB);
1664         if (rc == -EAGAIN)
1665                 goto findUniqueRetry;
1666
1667         return rc;
1668 }
1669
1670 int
1671 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
1672               const char *searchName, FILE_DIRECTORY_INFO * findData,
1673               T2_FFIRST_RSP_PARMS * findParms,
1674               const struct nls_table *nls_codepage, int *pUnicodeFlag,
1675               int *pUnixFlag)
1676 {
1677 /* level 257 SMB_ */
1678         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
1679         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
1680         char *response_data;
1681         int rc = 0;
1682         int bytes_returned;
1683         int name_len;
1684
1685         cFYI(1, ("In FindFirst"));
1686 findFirstRetry:
1687         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1688                       (void **) &pSMBr);
1689         if (rc)
1690                 return rc;
1691
1692         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1693                 name_len =
1694                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
1695                                   /* find define for this maxpathcomponent */
1696                                   , nls_codepage);
1697                 name_len++;     /* trailing null */
1698                 name_len *= 2;
1699         } else {                /* BB improve the check for buffer overruns BB */
1700                 name_len = strnlen(searchName, 530);
1701                 name_len++;     /* trailing null */
1702                 strncpy(pSMB->FileName, searchName, name_len);
1703         }
1704
1705         pSMB->TotalParameterCount = 12 + name_len /* includes null */ ;
1706         pSMB->TotalDataCount = 0;       /* no EAs */
1707         pSMB->MaxParameterCount = cpu_to_le16(10);
1708         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
1709                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1710         pSMB->MaxSetupCount = 0;
1711         pSMB->Reserved = 0;
1712         pSMB->Flags = 0;
1713         pSMB->Timeout = 0;
1714         pSMB->Reserved2 = 0;
1715         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1716         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
1717         pSMB->ParameterCount = pSMB->TotalParameterCount;
1718         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
1719         smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
1720         pSMB->DataCount = 0;
1721         pSMB->DataOffset = 0;
1722         pSMB->SetupCount = 1;   /* one byte no need to make endian neutral */
1723         pSMB->Reserved3 = 0;
1724         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
1725         pSMB->SearchAttributes =
1726             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1727                         ATTR_DIRECTORY);
1728         pSMB->SearchCount = cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO));       /* should this be shrunk even more ? */
1729         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
1730
1731         /* test for Unix extensions */
1732         if (tcon->ses->capabilities & CAP_UNIX) {
1733                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
1734                 *pUnixFlag = TRUE;
1735         } else {
1736                 pSMB->InformationLevel =
1737                     cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
1738                 *pUnixFlag = FALSE;
1739         }
1740         pSMB->SearchStorageType = 0;    /* BB what should we set this to? It is not clear if it matters BB */
1741         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1742         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1743
1744         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1745                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1746
1747         if (rc) {               /* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
1748                 cFYI(1, ("Error in FindFirst = %d", rc));
1749         } else {                /* decode response */
1750                 /* BB add safety checks for these memcpys */
1751                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
1752                         *pUnicodeFlag = TRUE;
1753                 else
1754                         *pUnicodeFlag = FALSE;
1755                 memcpy(findParms,
1756                        (char *) &pSMBr->hdr.Protocol +
1757                        le16_to_cpu(pSMBr->ParameterOffset),
1758                        sizeof (T2_FFIRST_RSP_PARMS));
1759                 /* search handle can stay LE and EAoffset not needed so not converted */
1760                 findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch);
1761                 findParms->LastNameOffset =
1762                     le16_to_cpu(findParms->LastNameOffset);
1763                 findParms->SearchCount = le16_to_cpu(findParms->SearchCount);
1764                 response_data =
1765                     (char *) &pSMBr->hdr.Protocol +
1766                     le16_to_cpu(pSMBr->DataOffset);
1767                 memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount));
1768         }
1769         if (pSMB)
1770                 cifs_buf_release(pSMB);
1771
1772         if (rc == -EAGAIN)
1773                 goto findFirstRetry;
1774
1775         return rc;
1776 }
1777
1778 int
1779 CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
1780                 FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms,
1781                 const __u16 searchHandle, char * resume_file_name, int name_len,
1782                 __u32 resume_key, int *pUnicodeFlag, int *pUnixFlag)
1783 {
1784 /* level 257 SMB_ */
1785         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
1786         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
1787         char *response_data;
1788         int rc = 0;
1789         int bytes_returned;
1790
1791         cFYI(1, ("In FindNext"));
1792
1793         if(resume_file_name == NULL) {
1794                 return -EIO;
1795         }
1796         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1797                       (void **) &pSMBr);
1798         if (rc)
1799                 return rc;
1800
1801         pSMB->TotalParameterCount = 14; /* includes 2 bytes of null string, converted to LE below */
1802         pSMB->TotalDataCount = 0;       /* no EAs */
1803         pSMB->MaxParameterCount = cpu_to_le16(8);
1804         pSMB->MaxDataCount =
1805             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1806         pSMB->MaxSetupCount = 0;
1807         pSMB->Reserved = 0;
1808         pSMB->Flags = 0;
1809         pSMB->Timeout = 0;
1810         pSMB->Reserved2 = 0;
1811         pSMB->ParameterOffset =  cpu_to_le16(offsetof(
1812         struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
1813         pSMB->DataCount = 0;
1814         pSMB->DataOffset = 0;
1815         pSMB->SetupCount = 1;
1816         pSMB->Reserved3 = 0;
1817         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
1818         pSMB->SearchHandle = searchHandle;      /* always kept as le */
1819         findParms->SearchCount = 0;     /* set to zero in case of error */
1820         pSMB->SearchCount =
1821             cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO));
1822         /* test for Unix extensions */
1823         if (tcon->ses->capabilities & CAP_UNIX) {
1824                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
1825                 *pUnixFlag = TRUE;
1826         } else {
1827                 pSMB->InformationLevel =
1828                     cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
1829                 *pUnixFlag = FALSE;
1830         }
1831         pSMB->ResumeKey = resume_key;
1832         pSMB->SearchFlags =
1833             cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
1834         /* BB add check to make sure we do not cross end of smb */
1835         if(name_len < CIFS_MAX_MSGSIZE) {
1836                 memcpy(pSMB->ResumeFileName, resume_file_name, name_len);
1837                 pSMB->ByteCount += name_len;
1838         }
1839         pSMB->TotalParameterCount += name_len;
1840         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1841         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
1842         pSMB->ParameterCount = pSMB->TotalParameterCount;
1843         /* BB improve error handling here */
1844         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1845         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1846
1847         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1848                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1849
1850         if (rc) {
1851                 if (rc == -EBADF)
1852                         rc = 0; /* search probably was closed at end of search above */
1853                 else
1854                         cFYI(1, ("FindNext returned = %d", rc));
1855         } else {                /* decode response */
1856                 /* BB add safety checks for these memcpys */
1857                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
1858                         *pUnicodeFlag = TRUE;
1859                 else
1860                         *pUnicodeFlag = FALSE;
1861                 memcpy(findParms,
1862                        (char *) &pSMBr->hdr.Protocol +
1863                        le16_to_cpu(pSMBr->ParameterOffset),
1864                        sizeof (T2_FNEXT_RSP_PARMS));
1865                 findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch);
1866                 findParms->LastNameOffset =
1867                     le16_to_cpu(findParms->LastNameOffset);
1868                 findParms->SearchCount = le16_to_cpu(findParms->SearchCount);
1869                 response_data =
1870                     (char *) &pSMBr->hdr.Protocol +
1871                     le16_to_cpu(pSMBr->DataOffset);
1872                 memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount));
1873         }
1874         if (pSMB)
1875                 cifs_buf_release(pSMB);
1876
1877         /* Note: On -EAGAIN error only caller can retry on handle based calls
1878                 since file handle passed in no longer valid */
1879
1880         return rc;
1881 }
1882
1883 int
1884 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
1885 {
1886         int rc = 0;
1887         FINDCLOSE_REQ *pSMB = NULL;
1888         CLOSE_RSP *pSMBr = NULL;
1889         int bytes_returned;
1890
1891         cFYI(1, ("In CIFSSMBFindClose"));
1892         rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB,
1893                       (void **) &pSMBr);
1894         /* no sense returning error if session restarted
1895                 file handle has been closed */
1896         if(rc == -EAGAIN)
1897                 return 0;
1898         if (rc)
1899                 return rc;
1900
1901         pSMB->FileID = searchHandle;
1902         pSMB->ByteCount = 0;
1903         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1904                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1905         if (rc) {
1906                 cERROR(1, ("Send error in FindClose = %d", rc));
1907         }
1908         if (pSMB)
1909                 cifs_buf_release(pSMB);
1910
1911         /* Since session is dead, search handle closed on server already */
1912         if (rc == -EAGAIN)
1913                 rc = 0;
1914
1915         return rc;
1916 }
1917
1918 int
1919 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
1920                 const unsigned char *searchName,
1921                 unsigned char **targetUNCs,
1922                 unsigned int *number_of_UNC_in_array,
1923                 const struct nls_table *nls_codepage)
1924 {
1925 /* TRANS2_GET_DFS_REFERRAL */
1926         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
1927         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
1928         struct dfs_referral_level_3 * referrals = NULL;
1929         int rc = 0;
1930         int bytes_returned;
1931         int name_len;
1932         unsigned int i;
1933         char * temp;
1934         *number_of_UNC_in_array = 0;
1935         *targetUNCs = NULL;
1936
1937         cFYI(1, ("In GetDFSRefer the path %s", searchName));
1938         if (ses == NULL)
1939                 return -ENODEV;
1940 getDFSRetry:
1941         rc = smb_init(SMB_COM_TRANSACTION2, 15, 0, (void **) &pSMB,
1942                       (void **) &pSMBr);
1943         if (rc)
1944                 return rc;
1945
1946         pSMB->hdr.Tid = ses->ipc_tid;
1947         pSMB->hdr.Uid = ses->Suid;
1948         if (ses->capabilities & CAP_STATUS32) {
1949                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
1950         }
1951         if (ses->capabilities & CAP_DFS) {
1952                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
1953         }
1954
1955         if (ses->capabilities & CAP_UNICODE) {
1956                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
1957                 name_len =
1958                     cifs_strtoUCS((wchar_t *) pSMB->RequestFileName,
1959                                   searchName, 530
1960                                   /* find define for this maxpathcomponent */
1961                                   , nls_codepage);
1962                 name_len++;     /* trailing null */
1963                 name_len *= 2;
1964         } else {                /* BB improve the check for buffer overruns BB */
1965                 name_len = strnlen(searchName, 530);
1966                 name_len++;     /* trailing null */
1967                 strncpy(pSMB->RequestFileName, searchName, name_len);
1968         }
1969
1970         pSMB->ParameterCount = 2 /* level */  + name_len /*includes null */ ;
1971         pSMB->TotalDataCount = 0;
1972         pSMB->DataCount = 0;
1973         pSMB->DataOffset = 0;
1974         pSMB->MaxParameterCount = 0;
1975         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
1976         pSMB->MaxSetupCount = 0;
1977         pSMB->Reserved = 0;
1978         pSMB->Flags = 0;
1979         pSMB->Timeout = 0;
1980         pSMB->Reserved2 = 0;
1981         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1982         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
1983         pSMB->SetupCount = 1;
1984         pSMB->Reserved3 = 0;
1985         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
1986         pSMB->ByteCount = pSMB->ParameterCount + 3 /* pad */ ;
1987         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
1988         pSMB->TotalParameterCount = pSMB->ParameterCount;
1989         pSMB->MaxReferralLevel = cpu_to_le16(3);
1990         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1991         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1992
1993         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
1994                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1995         if (rc) {
1996                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
1997         } else {                /* decode response */
1998 /* BB Add logic to parse referrals here */
1999                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
2000                 pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
2001                 cFYI(1,
2002                      ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
2003                       pSMBr->ByteCount, pSMBr->DataOffset));
2004                 if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512))       /* BB also check enough total bytes returned */
2005                         rc = -EIO;      /* bad smb */
2006                 else {
2007                         referrals = 
2008                             (struct dfs_referral_level_3 *) 
2009                                         (8 /* sizeof start of data block */ +
2010                                         pSMBr->DataOffset +
2011                                         (char *) &pSMBr->hdr.Protocol); 
2012                         cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive));
2013                         /* BB This field is actually two bytes in from start of
2014                            data block so we could do safety check that DataBlock
2015                            begins at address of pSMBr->NumberOfReferrals */
2016                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2017
2018                         /* BB Fix below so can return more than one referral */
2019                         if(*number_of_UNC_in_array > 1)
2020                                 *number_of_UNC_in_array = 1;
2021
2022                         /* get the length of the strings describing refs */
2023                         name_len = 0;
2024                         for(i=0;i<*number_of_UNC_in_array;i++) {
2025                                 /* make sure that DfsPathOffset not past end */
2026                                 referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset);
2027                                 if(referrals->DfsPathOffset > pSMBr->DataCount) {
2028                                         /* if invalid referral, stop here and do 
2029                                         not try to copy any more */
2030                                         *number_of_UNC_in_array = i;
2031                                         break;
2032                                 } 
2033                                 temp = ((char *)referrals) + referrals->DfsPathOffset;
2034
2035                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2036                                         name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount);
2037                                 } else {
2038                                         name_len += strnlen(temp,pSMBr->DataCount);
2039                                 }
2040                                 referrals++;
2041                                 /* BB add check that referral pointer does not fall off end PDU */
2042                                 
2043                         }
2044                         /* BB add check for name_len bigger than bcc */
2045                         *targetUNCs = 
2046                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2047                         /* copy the ref strings */
2048                         referrals =  
2049                             (struct dfs_referral_level_3 *) 
2050                                         (8 /* sizeof data hdr */ +
2051                                         pSMBr->DataOffset + 
2052                                         (char *) &pSMBr->hdr.Protocol);
2053
2054                         for(i=0;i<*number_of_UNC_in_array;i++) {
2055                                 temp = ((char *)referrals) + referrals->DfsPathOffset;
2056                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2057                                         cifs_strfromUCS_le(*targetUNCs,
2058                                                 (wchar_t *) temp, name_len, nls_codepage);
2059                                 } else {
2060                                         strncpy(*targetUNCs,temp,name_len);
2061                                 }
2062                                 /*  BB update target_uncs pointers */
2063                                 referrals++;
2064                         }
2065                         temp = *targetUNCs;
2066                         temp[name_len] = 0;
2067                 }
2068
2069         }
2070         if (pSMB)
2071                 cifs_buf_release(pSMB);
2072
2073         if (rc == -EAGAIN)
2074                 goto getDFSRetry;
2075
2076         return rc;
2077 }
2078
2079 int
2080 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
2081                struct kstatfs *FSData, const struct nls_table *nls_codepage)
2082 {
2083 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
2084         TRANSACTION2_QFSI_REQ *pSMB = NULL;
2085         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2086         FILE_SYSTEM_INFO *response_data;
2087         int rc = 0;
2088         int bytes_returned = 0;
2089
2090         cFYI(1, ("In QFSInfo"));
2091 QFSInfoRetry:
2092         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2093                       (void **) &pSMBr);
2094         if (rc)
2095                 return rc;
2096
2097         pSMB->TotalParameterCount = 2;  /* level */
2098         pSMB->TotalDataCount = 0;
2099         pSMB->MaxParameterCount = cpu_to_le16(2);
2100         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2101         pSMB->MaxSetupCount = 0;
2102         pSMB->Reserved = 0;
2103         pSMB->Flags = 0;
2104         pSMB->Timeout = 0;
2105         pSMB->Reserved2 = 0;
2106         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
2107         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
2108         pSMB->ParameterCount = pSMB->TotalParameterCount;
2109         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2110         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
2111         pSMB->DataCount = 0;
2112         pSMB->DataOffset = 0;
2113         pSMB->SetupCount = 1;
2114         pSMB->Reserved3 = 0;
2115         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
2116         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
2117         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2118         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2119
2120         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2121                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2122         if (rc) {
2123                 cERROR(1, ("Send error in QFSInfo = %d", rc));
2124         } else {                /* decode response */
2125                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
2126                 cFYI(1,
2127                      ("Decoding qfsinfo response.  BCC: %d  Offset %d",
2128                       pSMBr->ByteCount, pSMBr->DataOffset));
2129                 if ((pSMBr->ByteCount < 24) || (pSMBr->DataOffset > 512))       /* BB also check enough total bytes returned */
2130                         rc = -EIO;      /* bad smb */
2131                 else {
2132                         response_data =
2133                             (FILE_SYSTEM_INFO
2134                              *) (((char *) &pSMBr->hdr.Protocol) +
2135                                  pSMBr->DataOffset);
2136                         FSData->f_bsize =
2137                             le32_to_cpu(response_data->BytesPerSector) *
2138                             le32_to_cpu(response_data->
2139                                         SectorsPerAllocationUnit);
2140                         FSData->f_blocks =
2141                             le64_to_cpu(response_data->TotalAllocationUnits);
2142                         FSData->f_bfree = FSData->f_bavail =
2143                             le64_to_cpu(response_data->FreeAllocationUnits);
2144                         cFYI(1,
2145                              ("Blocks: %lld  Free: %lld Block size %ld",
2146                               (unsigned long long)FSData->f_blocks,
2147                               (unsigned long long)FSData->f_bfree,
2148                               FSData->f_bsize));
2149                 }
2150         }
2151         if (pSMB)
2152                 cifs_buf_release(pSMB);
2153
2154         if (rc == -EAGAIN)
2155                 goto QFSInfoRetry;
2156
2157         return rc;
2158 }
2159
2160 int
2161 CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon,
2162                         const struct nls_table *nls_codepage)
2163 {
2164 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
2165         TRANSACTION2_QFSI_REQ *pSMB = NULL;
2166         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2167         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
2168         int rc = 0;
2169         int bytes_returned = 0;
2170
2171         cFYI(1, ("In QFSAttributeInfo"));
2172 QFSAttributeRetry:
2173         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2174                       (void **) &pSMBr);
2175         if (rc)
2176                 return rc;
2177
2178         pSMB->TotalParameterCount = 2;  /* level */
2179         pSMB->TotalDataCount = 0;
2180         pSMB->MaxParameterCount = cpu_to_le16(2);
2181         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2182         pSMB->MaxSetupCount = 0;
2183         pSMB->Reserved = 0;
2184         pSMB->Flags = 0;
2185         pSMB->Timeout = 0;
2186         pSMB->Reserved2 = 0;
2187         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
2188         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
2189         pSMB->ParameterCount = pSMB->TotalParameterCount;
2190         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2191         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
2192         pSMB->DataCount = 0;
2193         pSMB->DataOffset = 0;
2194         pSMB->SetupCount = 1;
2195         pSMB->Reserved3 = 0;
2196         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
2197         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
2198         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2199         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2200
2201         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2202                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2203         if (rc) {
2204                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
2205         } else {                /* decode response */
2206                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
2207                 if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) {     /* BB also check enough bytes returned */
2208                         rc = -EIO;      /* bad smb */
2209                 } else {
2210                         response_data =
2211                             (FILE_SYSTEM_ATTRIBUTE_INFO
2212                              *) (((char *) &pSMBr->hdr.Protocol) +
2213                                  pSMBr->DataOffset);
2214                         memcpy(&tcon->fsAttrInfo, response_data,
2215                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
2216                 }
2217         }
2218         if (pSMB)
2219                 cifs_buf_release(pSMB);
2220
2221         if (rc == -EAGAIN)
2222                 goto QFSAttributeRetry;
2223
2224         return rc;
2225 }
2226
2227 int
2228 CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon,
2229                      const struct nls_table *nls_codepage)
2230 {
2231 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
2232         TRANSACTION2_QFSI_REQ *pSMB = NULL;
2233         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2234         FILE_SYSTEM_DEVICE_INFO *response_data;
2235         int rc = 0;
2236         int bytes_returned = 0;
2237
2238         cFYI(1, ("In QFSDeviceInfo"));
2239 QFSDeviceRetry:
2240         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2241                       (void **) &pSMBr);
2242         if (rc)
2243                 return rc;
2244
2245         pSMB->TotalParameterCount = 2;  /* level */
2246         pSMB->TotalDataCount = 0;
2247         pSMB->MaxParameterCount = cpu_to_le16(2);
2248         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2249         pSMB->MaxSetupCount = 0;
2250         pSMB->Reserved = 0;
2251         pSMB->Flags = 0;
2252         pSMB->Timeout = 0;
2253         pSMB->Reserved2 = 0;
2254         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
2255         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
2256         pSMB->ParameterCount = pSMB->TotalParameterCount;
2257         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2258         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
2259
2260         pSMB->DataCount = 0;
2261         pSMB->DataOffset = 0;
2262         pSMB->SetupCount = 1;
2263         pSMB->Reserved3 = 0;
2264         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
2265         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
2266         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2267         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2268
2269         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2270                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2271         if (rc) {
2272                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
2273         } else {                /* decode response */
2274                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
2275                 if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO))
2276                  || (pSMBr->DataOffset > 512))
2277                         rc = -EIO;      /* bad smb */
2278                 else {
2279                         response_data =
2280                             (FILE_SYSTEM_DEVICE_INFO
2281                              *) (((char *) &pSMBr->hdr.Protocol) +
2282                                  pSMBr->DataOffset);
2283                         memcpy(&tcon->fsDevInfo, response_data,
2284                                sizeof (FILE_SYSTEM_DEVICE_INFO));
2285                 }
2286         }
2287         if (pSMB)
2288                 cifs_buf_release(pSMB);
2289
2290         if (rc == -EAGAIN)
2291                 goto QFSDeviceRetry;
2292
2293
2294         return rc;
2295 }
2296
2297 int
2298 CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon,
2299                    const struct nls_table *nls_codepage)
2300 {
2301 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
2302         TRANSACTION2_QFSI_REQ *pSMB = NULL;
2303         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2304         FILE_SYSTEM_UNIX_INFO *response_data;
2305         int rc = 0;
2306         int bytes_returned = 0;
2307
2308         cFYI(1, ("In QFSUnixInfo"));
2309 QFSUnixRetry:
2310         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2311                       (void **) &pSMBr);
2312         if (rc)
2313                 return rc;
2314
2315         pSMB->ParameterCount = 2;       /* level */
2316         pSMB->TotalDataCount = 0;
2317         pSMB->DataCount = 0;
2318         pSMB->DataOffset = 0;
2319         pSMB->MaxParameterCount = cpu_to_le16(2);
2320         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
2321         pSMB->MaxSetupCount = 0;
2322         pSMB->Reserved = 0;
2323         pSMB->Flags = 0;
2324         pSMB->Timeout = 0;
2325         pSMB->Reserved2 = 0;
2326         pSMB->ByteCount = pSMB->ParameterCount + 1 /* pad */ ;
2327         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2328         pSMB->TotalParameterCount = pSMB->ParameterCount;
2329         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
2330         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
2331         pSMB->SetupCount = 1;
2332         pSMB->Reserved3 = 0;
2333         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
2334         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
2335         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2336         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2337
2338         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2339                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2340         if (rc) {
2341                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
2342         } else {                /* decode response */
2343                 pSMBr->DataOffset = cpu_to_le16(pSMBr->DataOffset);
2344                 if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) {
2345                         rc = -EIO;      /* bad smb */
2346                 } else {
2347                         response_data =
2348                             (FILE_SYSTEM_UNIX_INFO
2349                              *) (((char *) &pSMBr->hdr.Protocol) +
2350                                  pSMBr->DataOffset);
2351                         memcpy(&tcon->fsUnixInfo, response_data,
2352                                sizeof (FILE_SYSTEM_UNIX_INFO));
2353                 }
2354         }
2355         if (pSMB)
2356                 cifs_buf_release(pSMB);
2357
2358         if (rc == -EAGAIN)
2359                 goto QFSUnixRetry;
2360
2361
2362         return rc;
2363 }
2364
2365 /* We can not use write of zero bytes trick to 
2366    set file size due to need for large file support.  Also note that 
2367    this SetPathInfo is preferred to SetFileInfo based method in next 
2368    routine which is only needed to work around a sharing violation bug
2369    in Samba which this routine can run into */
2370
2371 int
2372 CIFSSMBSetEOF(int xid, struct cifsTconInfo *tcon, char *fileName,
2373               __u64 size, int SetAllocation, const struct nls_table *nls_codepage)
2374 {
2375         struct smb_com_transaction2_spi_req *pSMB = NULL;
2376         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2377         struct file_end_of_file_info *parm_data;
2378         int name_len;
2379         int rc = 0;
2380         int bytes_returned = 0;
2381
2382         cFYI(1, ("In SetEOF"));
2383 SetEOFRetry:
2384         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2385                       (void **) &pSMBr);
2386         if (rc)
2387                 return rc;
2388
2389         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2390                 name_len =
2391                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
2392                                   /* find define for this maxpathcomponent */
2393                                   , nls_codepage);
2394                 name_len++;     /* trailing null */
2395                 name_len *= 2;
2396         } else {                /* BB improve the check for buffer overruns BB */
2397                 name_len = strnlen(fileName, 530);
2398                 name_len++;     /* trailing null */
2399                 strncpy(pSMB->FileName, fileName, name_len);
2400         }
2401         pSMB->ParameterCount = 6 + name_len;
2402         pSMB->DataCount = sizeof (struct file_end_of_file_info);
2403         pSMB->MaxParameterCount = cpu_to_le16(2);
2404         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2405         pSMB->MaxSetupCount = 0;
2406         pSMB->Reserved = 0;
2407         pSMB->Flags = 0;
2408         pSMB->Timeout = 0;
2409         pSMB->Reserved2 = 0;
2410         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
2411                                      InformationLevel) - 4;
2412         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
2413         if(SetAllocation) {
2414                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
2415                     pSMB->InformationLevel =
2416                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
2417                 else
2418                     pSMB->InformationLevel =
2419                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
2420         } else /* Set File Size */  {    
2421             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
2422                     pSMB->InformationLevel =
2423                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
2424             else
2425                     pSMB->InformationLevel =
2426                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
2427         }
2428
2429         parm_data =
2430             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
2431                                        pSMB->DataOffset);
2432         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
2433         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
2434         pSMB->SetupCount = 1;
2435         pSMB->Reserved3 = 0;
2436         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2437         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
2438         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
2439         pSMB->TotalDataCount = pSMB->DataCount;
2440         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2441         pSMB->TotalParameterCount = pSMB->ParameterCount;
2442         pSMB->Reserved4 = 0;
2443         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2444         parm_data->FileSize = cpu_to_le64(size);
2445         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2446         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2447                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2448         if (rc) {
2449                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
2450         }
2451
2452         if (pSMB)
2453                 cifs_buf_release(pSMB);
2454
2455         if (rc == -EAGAIN)
2456                 goto SetEOFRetry;
2457
2458         return rc;
2459 }
2460
2461 int
2462 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
2463                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
2464 {
2465         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
2466         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2467         char *data_offset;
2468         struct file_end_of_file_info *parm_data;
2469         int rc = 0;
2470         int bytes_returned = 0;
2471         __u32 tmp;
2472
2473         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
2474                         (long long)size));
2475         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2476                       (void **) &pSMBr);
2477         if (rc)
2478                 return rc;
2479
2480         tmp = cpu_to_le32(pid_of_opener);  /* override pid of current process
2481                                          so network fid will be valid */
2482         pSMB->hdr.Pid = tmp & 0xFFFF;
2483         tmp >>= 16;
2484         pSMB->hdr.PidHigh = tmp & 0xFFFF;
2485     
2486         pSMB->ParameterCount = 6;
2487         pSMB->MaxSetupCount = 0;
2488         pSMB->Reserved = 0;
2489         pSMB->Flags = 0;
2490         pSMB->Timeout = 0;
2491         pSMB->Reserved2 = 0;
2492         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req,
2493                                      Fid) - 4;
2494         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
2495
2496         data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;        
2497
2498         pSMB->DataCount = sizeof(struct file_end_of_file_info);
2499         pSMB->MaxParameterCount = cpu_to_le16(2);
2500         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2501         pSMB->SetupCount = 1;
2502         pSMB->Reserved3 = 0;
2503         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2504         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
2505         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
2506         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2507         pSMB->TotalDataCount = pSMB->DataCount;
2508         pSMB->TotalParameterCount = pSMB->ParameterCount;
2509         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
2510         parm_data =
2511                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
2512                         pSMB->DataOffset);
2513         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */
2514         parm_data->FileSize = size;
2515         pSMB->Fid = fid;
2516         if(SetAllocation) {
2517                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
2518                         pSMB->InformationLevel =
2519                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
2520                 else
2521                         pSMB->InformationLevel =
2522                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
2523         } else /* Set File Size */  {    
2524             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
2525                     pSMB->InformationLevel =
2526                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
2527             else
2528                     pSMB->InformationLevel =
2529                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
2530         }
2531         pSMB->Reserved4 = 0;
2532         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2533         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2534         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2535                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2536         if (rc) {
2537                 cFYI(1,
2538                      ("Send error in SetFileInfo (SetFileSize) = %d",
2539                       rc));
2540         }
2541
2542         if (pSMB)
2543                 cifs_buf_release(pSMB);
2544
2545         /* Note: On -EAGAIN error only caller can retry on handle based calls 
2546                 since file handle passed in no longer valid */
2547
2548         return rc;
2549 }
2550
2551 int
2552 CIFSSMBSetTimes(int xid, struct cifsTconInfo *tcon, char *fileName,
2553                 FILE_BASIC_INFO * data, const struct nls_table *nls_codepage)
2554 {
2555         TRANSACTION2_SPI_REQ *pSMB = NULL;
2556         TRANSACTION2_SPI_RSP *pSMBr = NULL;
2557         int name_len;
2558         int rc = 0;
2559         int bytes_returned = 0;
2560         char *data_offset;
2561
2562         cFYI(1, ("In SetTimes"));
2563
2564 SetTimesRetry:
2565         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2566                       (void **) &pSMBr);
2567         if (rc)
2568                 return rc;
2569
2570         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2571                 name_len =
2572                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
2573                                   /* find define for this maxpathcomponent */
2574                                   , nls_codepage);
2575                 name_len++;     /* trailing null */
2576                 name_len *= 2;
2577         } else {                /* BB improve the check for buffer overruns BB */
2578                 name_len = strnlen(fileName, 530);
2579                 name_len++;     /* trailing null */
2580                 strncpy(pSMB->FileName, fileName, name_len);
2581         }
2582
2583         pSMB->ParameterCount = 6 + name_len;
2584         pSMB->DataCount = sizeof (FILE_BASIC_INFO);
2585         pSMB->MaxParameterCount = cpu_to_le16(2);
2586         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2587         pSMB->MaxSetupCount = 0;
2588         pSMB->Reserved = 0;
2589         pSMB->Flags = 0;
2590         pSMB->Timeout = 0;
2591         pSMB->Reserved2 = 0;
2592         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
2593                                      InformationLevel) - 4;
2594         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
2595         data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
2596         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
2597         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
2598         pSMB->SetupCount = 1;
2599         pSMB->Reserved3 = 0;
2600         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2601         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
2602
2603         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
2604         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2605         pSMB->TotalDataCount = pSMB->DataCount;
2606         pSMB->TotalParameterCount = pSMB->ParameterCount;
2607         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
2608                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
2609         else
2610                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
2611         pSMB->Reserved4 = 0;
2612         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2613         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
2614         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2615         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2616                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2617         if (rc) {
2618                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
2619         }
2620
2621         if (pSMB)
2622                 cifs_buf_release(pSMB);
2623
2624         if (rc == -EAGAIN)
2625                 goto SetTimesRetry;
2626
2627         return rc;
2628 }
2629
2630 int
2631 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
2632                     char *fileName, __u64 mode, __u64 uid, __u64 gid,
2633                     dev_t device, const struct nls_table *nls_codepage)
2634 {
2635         TRANSACTION2_SPI_REQ *pSMB = NULL;
2636         TRANSACTION2_SPI_RSP *pSMBr = NULL;
2637         int name_len;
2638         int rc = 0;
2639         int bytes_returned = 0;
2640         FILE_UNIX_BASIC_INFO *data_offset;
2641
2642         cFYI(1, ("In SetUID/GID/Mode"));
2643 setPermsRetry:
2644         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2645                       (void **) &pSMBr);
2646         if (rc)
2647                 return rc;
2648
2649         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2650                 name_len =
2651                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
2652                                   /* find define for this maxpathcomponent */
2653                                   , nls_codepage);
2654                 name_len++;     /* trailing null */
2655                 name_len *= 2;
2656         } else {                /* BB improve the check for buffer overruns BB */
2657                 name_len = strnlen(fileName, 530);
2658                 name_len++;     /* trailing null */
2659                 strncpy(pSMB->FileName, fileName, name_len);
2660         }
2661
2662         pSMB->ParameterCount = 6 + name_len;
2663         pSMB->DataCount = sizeof (FILE_UNIX_BASIC_INFO);
2664         pSMB->MaxParameterCount = cpu_to_le16(2);
2665         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2666         pSMB->MaxSetupCount = 0;
2667         pSMB->Reserved = 0;
2668         pSMB->Flags = 0;
2669         pSMB->Timeout = 0;
2670         pSMB->Reserved2 = 0;
2671         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
2672                                      InformationLevel) - 4;
2673         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
2674         data_offset =
2675             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
2676                                       pSMB->DataOffset);
2677         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
2678         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
2679         pSMB->SetupCount = 1;
2680         pSMB->Reserved3 = 0;
2681         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2682         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
2683         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2684         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
2685         pSMB->TotalParameterCount = pSMB->ParameterCount;
2686         pSMB->TotalDataCount = pSMB->DataCount;
2687         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
2688         pSMB->Reserved4 = 0;
2689         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2690         data_offset->Uid = cpu_to_le64(uid);
2691         data_offset->Gid = cpu_to_le64(gid);
2692         /* better to leave device as zero when it is  */
2693         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
2694         data_offset->DevMinor = cpu_to_le64(MINOR(device));
2695         data_offset->Permissions = cpu_to_le64(mode);
2696         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2697         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2698                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2699         if (rc) {
2700                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
2701         }
2702
2703         if (pSMB)
2704                 cifs_buf_release(pSMB);
2705         if (rc == -EAGAIN)
2706                 goto setPermsRetry;
2707         return rc;
2708 }