VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[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 #ifdef CONFIG_CIFS_POSIX
41 static struct {
42         int index;
43         char *name;
44 } protocols[] = {
45         {CIFS_PROT, "\2NT LM 0.12"}, 
46         {CIFS_PROT, "\2POSIX 2"},
47         {BAD_PROT, "\2"}
48 };
49 #else
50 static struct {
51         int index;
52         char *name;
53 } protocols[] = {
54         {CIFS_PROT, "\2NT LM 0.12"}, 
55         {BAD_PROT, "\2"}
56 };
57 #endif
58
59
60 /* Mark as invalid, all open files on tree connections since they
61    were closed when session to server was lost */
62 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
63 {
64         struct cifsFileInfo *open_file = NULL;
65         struct list_head * tmp;
66         struct list_head * tmp1;
67
68 /* list all files open on tree connection and mark them invalid */
69         write_lock(&GlobalSMBSeslock);
70         list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
71                 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
72                 if(open_file) {
73                         open_file->invalidHandle = TRUE;
74                 }
75         }
76         write_unlock(&GlobalSMBSeslock);
77         /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */
78 }
79
80 static int
81 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
82          void **request_buf /* returned */ ,
83          void **response_buf /* returned */ )
84 {
85         int rc = 0;
86
87         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
88            check for tcp and smb session status done differently
89            for those three - in the calling routine */
90         if(tcon) {
91                 if((tcon->ses) && (tcon->ses->server)){
92                         struct nls_table *nls_codepage;
93                                 /* Give Demultiplex thread up to 10 seconds to 
94                                         reconnect, should be greater than cifs socket
95                                         timeout which is 7 seconds */
96                         while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
97                                 wait_event_interruptible_timeout(tcon->ses->server->response_q,
98                                         (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
99                                 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
100                                         /* on "soft" mounts we wait once */
101                                         if((tcon->retry == FALSE) || 
102                                            (tcon->ses->status == CifsExiting)) {
103                                                 cFYI(1,("gave up waiting on reconnect in smb_init"));
104                                                 return -EHOSTDOWN;
105                                         } /* else "hard" mount - keep retrying until 
106                                         process is killed or server comes back up */
107                                 } else /* TCP session is reestablished now */
108                                         break;
109                                  
110                         }
111                         
112                         nls_codepage = load_nls_default();
113                 /* need to prevent multiple threads trying to
114                 simultaneously reconnect the same SMB session */
115                         down(&tcon->ses->sesSem);
116                         if(tcon->ses->status == CifsNeedReconnect)
117                                 rc = cifs_setup_session(0, tcon->ses, nls_codepage);
118                         if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
119                                 mark_open_files_invalid(tcon);
120                                 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
121                                         nls_codepage);
122                                 up(&tcon->ses->sesSem);
123                                 if(rc == 0)
124                                         atomic_inc(&tconInfoReconnectCount);
125
126                                 cFYI(1, ("reconnect tcon rc = %d", rc));
127                                 /* Removed call to reopen open files here - 
128                                         it is safer (and faster) to reopen files
129                                         one at a time as needed in read and write */
130
131                                 /* Check if handle based operation so we 
132                                         know whether we can continue or not without
133                                         returning to caller to reset file handle */
134                                 switch(smb_command) {
135                                         case SMB_COM_READ_ANDX:
136                                         case SMB_COM_WRITE_ANDX:
137                                         case SMB_COM_CLOSE:
138                                         case SMB_COM_FIND_CLOSE2:
139                                         case SMB_COM_LOCKING_ANDX: {
140                                                 unload_nls(nls_codepage);
141                                                 return -EAGAIN;
142                                         }
143                                 }
144                         } else {
145                                 up(&tcon->ses->sesSem);
146                         }
147                         unload_nls(nls_codepage);
148
149                 } else {
150                         return -EIO;
151                 }
152         }
153         if(rc)
154                 return rc;
155
156         *request_buf = cifs_buf_get();
157         if (*request_buf == 0) {
158                 /* BB should we add a retry in here if not a writepage? */
159                 return -ENOMEM;
160         }
161     /* Although the original thought was we needed the response buf for  */
162     /* potential retries of smb operations it turns out we can determine */
163     /* from the mid flags when the request buffer can be resent without  */
164     /* having to use a second distinct buffer for the response */
165         *response_buf = *request_buf; 
166
167         header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
168                         wct /*wct */ );
169
170 #ifdef CONFIG_CIFS_STATS
171         if(tcon != NULL) {
172                 atomic_inc(&tcon->num_smbs_sent);
173         }
174 #endif
175         return rc;
176 }
177
178 int
179 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
180 {
181         NEGOTIATE_REQ *pSMB;
182         NEGOTIATE_RSP *pSMBr;
183         int rc = 0;
184         int bytes_returned;
185         struct TCP_Server_Info * server;
186
187         if(ses->server)
188                 server = ses->server;
189         else {
190                 rc = -EIO;
191                 return rc;
192         }
193         rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
194                       (void **) &pSMB, (void **) &pSMBr);
195         if (rc)
196                 return rc;
197
198         pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
199         if (extended_security)
200                 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
201
202         pSMB->ByteCount = strlen(protocols[0].name) + 1;
203         strncpy(pSMB->DialectsArray, protocols[0].name, 30);    
204     /* null guaranteed to be at end of source and target buffers anyway */
205
206         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
207         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
208
209         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
210                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
211         if (rc == 0) {
212                 server->secMode = pSMBr->SecurityMode;  
213                 server->secType = NTLM; /* BB override default for NTLMv2 or krb*/
214                 /* one byte - no need to convert this or EncryptionKeyLen from le,*/
215                 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
216                 /* probably no need to store and check maxvcs */
217                 server->maxBuf =
218                         min(le32_to_cpu(pSMBr->MaxBufferSize),
219                         (__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE);
220                 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
221                 cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
222                 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
223                 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
224                 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
225         /* BB with UTC do we ever need to be using srvr timezone? */
226                 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
227                         memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
228                                CIFS_CRYPTO_KEY_SIZE);
229                 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
230                            && (pSMBr->EncryptionKeyLength == 0)) {
231                         /* decode security blob */
232                 } else
233                         rc = -EIO;
234
235                 /* BB might be helpful to save off the domain of server here */
236
237                 if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) {
238                         if (pSMBr->ByteCount < 16)
239                                 rc = -EIO;
240                         else if (pSMBr->ByteCount == 16) {
241                                 server->secType = RawNTLMSSP;
242                                 if (server->socketUseCount.counter > 1) {
243                                         if (memcmp
244                                                 (server->server_GUID,
245                                                 pSMBr->u.extended_response.
246                                                 GUID, 16) != 0) {
247                                                 cFYI(1,
248                                                         ("UID of server does not match previous connection to same ip address"));
249                                                 memcpy(server->
250                                                         server_GUID,
251                                                         pSMBr->u.
252                                                         extended_response.
253                                                         GUID, 16);
254                                         }
255                                 } else
256                                         memcpy(server->server_GUID,
257                                                pSMBr->u.extended_response.
258                                                GUID, 16);
259                         } else {
260                                 rc = decode_negTokenInit(pSMBr->u.
261                                                          extended_response.
262                                                          SecurityBlob,
263                                                          pSMBr->ByteCount -
264                                                          16, &server->secType);
265                         }
266                 } else
267                         server->capabilities &= ~CAP_EXTENDED_SECURITY;
268                 if(sign_CIFS_PDUs == FALSE) {        
269                         if(server->secMode & SECMODE_SIGN_REQUIRED)
270                                 cERROR(1,
271                                  ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
272                         server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
273                 } else if(sign_CIFS_PDUs == 1) {
274                         if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
275                                 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
276                 }
277                                 
278         }
279         if (pSMB)
280                 cifs_buf_release(pSMB);
281         return rc;
282 }
283
284 int
285 CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
286 {
287         struct smb_hdr *smb_buffer;
288         struct smb_hdr *smb_buffer_response;
289         int rc = 0;
290         int length;
291
292         cFYI(1, ("In tree disconnect"));
293         /*
294          *  If last user of the connection and
295          *  connection alive - disconnect it
296          *  If this is the last connection on the server session disconnect it
297          *  (and inside session disconnect we should check if tcp socket needs 
298          *  to be freed and kernel thread woken up).
299          */
300         if (tcon)
301                 down(&tcon->tconSem);
302         else
303                 return -EIO;
304
305         atomic_dec(&tcon->useCount);
306         if (atomic_read(&tcon->useCount) > 0) {
307                 up(&tcon->tconSem);
308                 return -EBUSY;
309         }
310
311         /* No need to return error on this operation if tid invalidated and 
312         closed on server already e.g. due to tcp session crashing */
313         if(tcon->tidStatus == CifsNeedReconnect) {
314                 up(&tcon->tconSem);
315                 return 0;  
316         }
317
318         if((tcon->ses == 0) || (tcon->ses->server == 0)) {    
319                 up(&tcon->tconSem);
320                 return -EIO;
321         }
322
323         rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
324                       (void **) &smb_buffer, (void **) &smb_buffer_response);
325         if (rc) {
326                 up(&tcon->tconSem);
327                 return rc;
328         }
329         rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
330                          &length, 0);
331         if (rc)
332                 cFYI(1, (" Tree disconnect failed %d", rc));
333
334         if (smb_buffer)
335                 cifs_buf_release(smb_buffer);
336         up(&tcon->tconSem);
337
338         /* No need to return error on this operation if tid invalidated and 
339         closed on server already e.g. due to tcp session crashing */
340         if (rc == -EAGAIN)
341                 rc = 0;
342
343         return rc;
344 }
345
346 int
347 CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
348 {
349         struct smb_hdr *smb_buffer_response;
350         LOGOFF_ANDX_REQ *pSMB;
351         int rc = 0;
352         int length;
353
354         cFYI(1, ("In SMBLogoff for session disconnect"));
355         if (ses)
356                 down(&ses->sesSem);
357         else
358                 return -EIO;
359
360         atomic_dec(&ses->inUse);
361         if (atomic_read(&ses->inUse) > 0) {
362                 up(&ses->sesSem);
363                 return -EBUSY;
364         }
365
366         rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL /* no tcon anymore */,
367                  (void **) &pSMB, (void **) &smb_buffer_response);
368
369         if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
370                 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
371
372         if (rc) {
373                 up(&ses->sesSem);
374                 return rc;
375         }
376
377         pSMB->hdr.Uid = ses->Suid;
378
379         pSMB->AndXCommand = 0xFF;
380         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
381                          smb_buffer_response, &length, 0);
382         if (ses->server) {
383                 atomic_dec(&ses->server->socketUseCount);
384                 if (atomic_read(&ses->server->socketUseCount) == 0) {
385                         spin_lock(&GlobalMid_Lock);
386                         ses->server->tcpStatus = CifsExiting;
387                         spin_unlock(&GlobalMid_Lock);
388                         rc = -ESHUTDOWN;
389                 }
390         }
391         if (pSMB)
392                 cifs_buf_release(pSMB);
393         up(&ses->sesSem);
394
395         /* if session dead then we do not need to do ulogoff,
396                 since server closed smb session, no sense reporting 
397                 error */
398         if (rc == -EAGAIN)
399                 rc = 0;
400         return rc;
401 }
402
403 int
404 CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
405                const char *fileName, const struct nls_table *nls_codepage)
406 {
407         DELETE_FILE_REQ *pSMB = NULL;
408         DELETE_FILE_RSP *pSMBr = NULL;
409         int rc = 0;
410         int bytes_returned;
411         int name_len;
412
413 DelFileRetry:
414         rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
415                       (void **) &pSMBr);
416         if (rc)
417                 return rc;
418
419         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
420                 name_len =
421                     cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, 530
422                                   /* find define for this maxpathcomponent */
423                                   , nls_codepage);
424                 name_len++;     /* trailing null */
425                 name_len *= 2;
426         } else {                /* BB improve the check for buffer overruns BB */
427                 name_len = strnlen(fileName, 530);
428                 name_len++;     /* trailing null */
429                 strncpy(pSMB->fileName, fileName, name_len);
430         }
431         pSMB->SearchAttributes =
432             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
433         pSMB->ByteCount = name_len + 1;
434         pSMB->BufferFormat = 0x04;
435         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
436         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
437         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
438                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
439         if (rc) {
440                 cFYI(1, ("Error in RMFile = %d", rc));
441         } 
442 #ifdef CONFIG_CIFS_STATS
443         else {
444                 atomic_inc(&tcon->num_deletes);
445         }
446 #endif
447
448         if (pSMB)
449                 cifs_buf_release(pSMB);
450         if (rc == -EAGAIN)
451                 goto DelFileRetry;
452
453         return rc;
454 }
455
456 int
457 CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
458              const char *dirName, const struct nls_table *nls_codepage)
459 {
460         DELETE_DIRECTORY_REQ *pSMB = NULL;
461         DELETE_DIRECTORY_RSP *pSMBr = NULL;
462         int rc = 0;
463         int bytes_returned;
464         int name_len;
465
466         cFYI(1, ("In CIFSSMBRmDir"));
467 RmDirRetry:
468         rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
469                       (void **) &pSMBr);
470         if (rc)
471                 return rc;
472
473         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
474                 name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, 530
475                                 /* find define for this maxpathcomponent */
476                                 , nls_codepage);
477                 name_len++;     /* trailing null */
478                 name_len *= 2;
479         } else {                /* BB improve the check for buffer overruns BB */
480                 name_len = strnlen(dirName, 530);
481                 name_len++;     /* trailing null */
482                 strncpy(pSMB->DirName, dirName, name_len);
483         }
484
485         pSMB->ByteCount = name_len + 1;
486         pSMB->BufferFormat = 0x04;
487         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
488         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
489         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
490                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
491         if (rc) {
492                 cFYI(1, ("Error in RMDir = %d", rc));
493         }
494 #ifdef CONFIG_CIFS_STATS
495         else {
496                 atomic_inc(&tcon->num_rmdirs);
497         }
498 #endif
499
500         if (pSMB)
501                 cifs_buf_release(pSMB);
502         if (rc == -EAGAIN)
503                 goto RmDirRetry;
504         return rc;
505 }
506
507 int
508 CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
509              const char *name, const struct nls_table *nls_codepage)
510 {
511         int rc = 0;
512         CREATE_DIRECTORY_REQ *pSMB = NULL;
513         CREATE_DIRECTORY_RSP *pSMBr = NULL;
514         int bytes_returned;
515         int name_len;
516
517         cFYI(1, ("In CIFSSMBMkDir"));
518 MkDirRetry:
519         rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
520                       (void **) &pSMBr);
521         if (rc)
522                 return rc;
523
524         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
525                 name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, 530
526                                          /* find define for this maxpathcomponent */
527                                          , nls_codepage);
528                 name_len++;     /* trailing null */
529                 name_len *= 2;
530         } else {                /* BB improve the check for buffer overruns BB */
531                 name_len = strnlen(name, 530);
532                 name_len++;     /* trailing null */
533                 strncpy(pSMB->DirName, name, name_len);
534         }
535
536         pSMB->ByteCount = name_len + 1 /* for buf format */ ;
537         pSMB->BufferFormat = 0x04;
538         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
539         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
540         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
541                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
542         if (rc) {
543                 cFYI(1, ("Error in Mkdir = %d", rc));
544         }
545 #ifdef CONFIG_CIFS_STATS
546         else {
547                 atomic_inc(&tcon->num_mkdirs);
548         }
549 #endif
550         if (pSMB)
551                 cifs_buf_release(pSMB);
552         if (rc == -EAGAIN)
553                 goto MkDirRetry;
554         return rc;
555 }
556
557 int
558 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
559             const char *fileName, const int openDisposition,
560             const int access_flags, const int create_options, __u16 * netfid,
561             int *pOplock, FILE_ALL_INFO * pfile_info, 
562             const struct nls_table *nls_codepage)
563 {
564         int rc = -EACCES;
565         OPEN_REQ *pSMB = NULL;
566         OPEN_RSP *pSMBr = NULL;
567         int bytes_returned;
568         int name_len;
569
570 openRetry:
571         rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
572                       (void **) &pSMBr);
573         if (rc)
574                 return rc;
575
576         pSMB->AndXCommand = 0xFF;       /* none */
577
578         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
579                 pSMB->ByteCount = 1;    /* account for one byte pad to word boundary */
580                 name_len =
581                     cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1),
582                                   fileName, 530
583                                   /* find define for this maxpathcomponent */
584                                   , nls_codepage);
585                 name_len++;     /* trailing null */
586                 name_len *= 2;
587                 pSMB->NameLength = cpu_to_le16(name_len);
588         } else {                /* BB improve the check for buffer overruns BB */
589                 pSMB->ByteCount = 0;    /* no pad */
590                 name_len = strnlen(fileName, 530);
591                 name_len++;     /* trailing null */
592                 pSMB->NameLength = cpu_to_le16(name_len);
593                 strncpy(pSMB->fileName, fileName, name_len);
594         }
595         if (*pOplock & REQ_OPLOCK)
596                 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
597         else if (*pOplock & REQ_BATCHOPLOCK) {
598                 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
599         }
600         pSMB->DesiredAccess = cpu_to_le32(access_flags);
601         pSMB->AllocationSize = 0;
602         pSMB->FileAttributes = ATTR_NORMAL;
603         /* XP does not handle ATTR_POSIX_SEMANTICS */
604         /* but it helps speed up case sensitive checks for other
605         servers such as Samba */
606         if (tcon->ses->capabilities & CAP_UNIX)
607                 pSMB->FileAttributes |= ATTR_POSIX_SEMANTICS;
608
609         /* if ((omode & S_IWUGO) == 0)
610                 pSMB->FileAttributes |= ATTR_READONLY;*/
611         /*  Above line causes problems due to vfs splitting create into two
612                 pieces - need to set mode after file created not while it is
613                 being created */
614         pSMB->FileAttributes = cpu_to_le32(pSMB->FileAttributes);
615         pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
616         pSMB->CreateDisposition = cpu_to_le32(openDisposition);
617         pSMB->CreateOptions = cpu_to_le32(create_options);
618         pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/
619         pSMB->SecurityFlags =
620             cpu_to_le32(SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY);
621
622         pSMB->ByteCount += name_len;
623         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
624
625         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
626         /* long_op set to 1 to allow for oplock break timeouts */
627         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
628                          (struct smb_hdr *) pSMBr, &bytes_returned, 1);
629         if (rc) {
630                 cFYI(1, ("Error in Open = %d", rc));
631         } else {
632                 *pOplock = pSMBr->OplockLevel;  /* one byte no need to le_to_cpu */
633                 *netfid = pSMBr->Fid;   /* cifs fid stays in le */
634                 /* Let caller know file was created so we can set the mode. */
635                 /* Do we care about the CreateAction in any other cases? */
636                 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
637                         *pOplock |= CIFS_CREATE_ACTION; 
638                 if(pfile_info) {
639                     memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
640                         36 /* CreationTime to Attributes */);
641                     /* the file_info buf is endian converted by caller */
642                     pfile_info->AllocationSize = pSMBr->AllocationSize;
643                     pfile_info->EndOfFile = pSMBr->EndOfFile;
644                     pfile_info->NumberOfLinks = cpu_to_le32(1);
645                 }
646
647 #ifdef CONFIG_CIFS_STATS
648                 atomic_inc(&tcon->num_opens);
649 #endif
650         }
651         if (pSMB)
652                 cifs_buf_release(pSMB);
653         if (rc == -EAGAIN)
654                 goto openRetry;
655         return rc;
656 }
657
658 /* If no buffer passed in, then caller wants to do the copy
659         as in the case of readpages so the SMB buffer must be
660         freed by the caller */
661
662 int
663 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
664             const int netfid, const unsigned int count,
665             const __u64 lseek, unsigned int *nbytes, char **buf)
666 {
667         int rc = -EACCES;
668         READ_REQ *pSMB = NULL;
669         READ_RSP *pSMBr = NULL;
670         char *pReadData = NULL;
671         int bytes_returned;
672
673         *nbytes = 0;
674         rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
675                       (void **) &pSMBr);
676         if (rc)
677                 return rc;
678
679         /* tcon and ses pointer are checked in smb_init */
680         if (tcon->ses->server == NULL)
681                 return -ECONNABORTED;
682
683         pSMB->AndXCommand = 0xFF;       /* none */
684         pSMB->Fid = netfid;
685         pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
686         pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
687         pSMB->Remaining = 0;
688         pSMB->MaxCount = cpu_to_le16(count);
689         pSMB->MaxCountHigh = 0;
690         pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
691
692         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
693                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
694         if (rc) {
695                 cERROR(1, ("Send error in read = %d", rc));
696         } else {
697                 pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength);
698                 *nbytes = pSMBr->DataLength;
699                 /*check that DataLength would not go beyond end of SMB */
700                 if ((pSMBr->DataLength > CIFS_MAX_MSGSIZE) 
701                                 || (pSMBr->DataLength > count)) {
702                         cFYI(1,("bad length %d for count %d",pSMBr->DataLength,count));
703                         rc = -EIO;
704                         *nbytes = 0;
705                 } else {
706                         pReadData =
707                             (char *) (&pSMBr->hdr.Protocol) +
708                             le16_to_cpu(pSMBr->DataOffset);
709 /*                      if(rc = copy_to_user(buf, pReadData, pSMBr->DataLength)) {
710                                 cERROR(1,("Faulting on read rc = %d",rc));
711                                 rc = -EFAULT;
712                         }*/ /* can not use copy_to_user when using page cache*/
713                         if(*buf)
714                             memcpy(*buf,pReadData,pSMBr->DataLength);
715                 }
716         }
717         if (pSMB) {
718                 if(*buf)
719                         cifs_buf_release(pSMB);
720                 else
721                         *buf = (char *)pSMB;
722         }
723
724         /* Note: On -EAGAIN error only caller can retry on handle based calls 
725                 since file handle passed in no longer valid */
726         return rc;
727 }
728
729 int
730 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
731              const int netfid, const unsigned int count,
732              const __u64 offset, unsigned int *nbytes, const char *buf,
733              const int long_op)
734 {
735         int rc = -EACCES;
736         WRITE_REQ *pSMB = NULL;
737         WRITE_RSP *pSMBr = NULL;
738         int bytes_returned;
739
740         rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
741                       (void **) &pSMBr);
742         if (rc)
743                 return rc;
744         /* tcon and ses pointer are checked in smb_init */
745         if (tcon->ses->server == NULL)
746                 return -ECONNABORTED;
747
748         pSMB->AndXCommand = 0xFF;       /* none */
749         pSMB->Fid = netfid;
750         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
751         pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
752         pSMB->Remaining = 0;
753         if (count > ((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00))
754                 pSMB->DataLengthLow =
755                     (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00;
756         else
757                 pSMB->DataLengthLow = count;
758         pSMB->DataLengthHigh = 0;
759         pSMB->DataOffset =
760             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
761
762         memcpy(pSMB->Data,buf,pSMB->DataLengthLow);
763
764         pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ;
765         pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow);
766         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
767         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
768
769         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
770                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
771         if (rc) {
772                 cFYI(1, ("Send error in write = %d", rc));
773                 *nbytes = 0;
774         } else
775                 *nbytes = le16_to_cpu(pSMBr->Count);
776
777         if (pSMB)
778                 cifs_buf_release(pSMB);
779
780         /* Note: On -EAGAIN error only caller can retry on handle based calls 
781                 since file handle passed in no longer valid */
782
783         return rc;
784 }
785
786 int
787 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
788             const __u16 smb_file_id, const __u64 len,
789             const __u64 offset, const __u32 numUnlock,
790             const __u32 numLock, const __u8 lockType, const int waitFlag)
791 {
792         int rc = 0;
793         LOCK_REQ *pSMB = NULL;
794         LOCK_RSP *pSMBr = NULL;
795         int bytes_returned;
796         int timeout = 0;
797         __u64 temp;
798
799         cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
800         rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
801                       (void **) &pSMBr);
802         if (rc)
803                 return rc;
804
805         if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
806                 timeout = -1; /* no response expected */
807                 pSMB->Timeout = 0;
808         } else if (waitFlag == TRUE) {
809                 timeout = 3;  /* blocking operation, no timeout */
810                 pSMB->Timeout = -1; /* blocking - do not time out */
811         } else {
812                 pSMB->Timeout = 0;
813         }
814
815         pSMB->NumberOfLocks = cpu_to_le32(numLock);
816         pSMB->NumberOfUnlocks = cpu_to_le32(numUnlock);
817         pSMB->LockType = lockType;
818         pSMB->AndXCommand = 0xFF;       /* none */
819         pSMB->Fid = smb_file_id; /* netfid stays le */
820
821         if(numLock != 0) {
822                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
823                 /* BB where to store pid high? */
824                 temp = cpu_to_le64(len);
825                 pSMB->Locks[0].LengthLow = (__u32)(temp & 0xFFFFFFFF);
826                 pSMB->Locks[0].LengthHigh =  (__u32)(temp>>32);
827                 temp = cpu_to_le64(offset);
828                 pSMB->Locks[0].OffsetLow = (__u32)(temp & 0xFFFFFFFF);
829                 pSMB->Locks[0].OffsetHigh = (__u32)(temp>>32);
830                 pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE);
831         } else {
832                 /* oplock break */
833                 pSMB->ByteCount = 0;
834         }
835         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
836         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
837
838         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
839                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
840
841         if (rc) {
842                 cFYI(1, ("Send error in Lock = %d", rc));
843         }
844         if (pSMB)
845                 cifs_buf_release(pSMB);
846
847         /* Note: On -EAGAIN error only caller can retry on handle based calls 
848         since file handle passed in no longer valid */
849         return rc;
850 }
851
852 int
853 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
854 {
855         int rc = 0;
856         CLOSE_REQ *pSMB = NULL;
857         CLOSE_RSP *pSMBr = NULL;
858         int bytes_returned;
859         cFYI(1, ("In CIFSSMBClose"));
860
861 /* do not retry on dead session on close */
862         rc = smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB,
863                       (void **) &pSMBr);
864         if(rc == -EAGAIN)
865                 return 0;
866         if (rc)
867                 return rc;
868
869         pSMB->FileID = (__u16) smb_file_id;
870         pSMB->LastWriteTime = 0;
871         pSMB->ByteCount = 0;
872         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
873                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
874         if (rc) {
875                 if(rc!=-EINTR) {
876                         /* EINTR is expected when user ctl-c to kill app */
877                         cERROR(1, ("Send error in Close = %d", rc));
878                 }
879         }
880         if (pSMB)
881                 cifs_buf_release(pSMB);
882
883         /* Since session is dead, file will be closed on server already */
884         if(rc == -EAGAIN)
885                 rc = 0;
886
887         return rc;
888 }
889
890 int
891 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
892               const char *fromName, const char *toName,
893               const struct nls_table *nls_codepage)
894 {
895         int rc = 0;
896         RENAME_REQ *pSMB = NULL;
897         RENAME_RSP *pSMBr = NULL;
898         int bytes_returned;
899         int name_len, name_len2;
900
901         cFYI(1, ("In CIFSSMBRename"));
902 renameRetry:
903         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
904                       (void **) &pSMBr);
905         if (rc)
906                 return rc;
907
908         pSMB->BufferFormat = 0x04;
909         pSMB->SearchAttributes =
910             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
911                         ATTR_DIRECTORY);
912
913         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
914                 name_len =
915                     cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
916                                   /* find define for this maxpathcomponent */
917                                   , nls_codepage);
918                 name_len++;     /* trailing null */
919                 name_len *= 2;
920                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
921         /* protocol requires ASCII signature byte on Unicode string */
922                 pSMB->OldFileName[name_len + 1] = 0x00;
923                 name_len2 =
924                     cifs_strtoUCS((wchar_t *) & pSMB->
925                                   OldFileName[name_len + 2], toName, 530,
926                                   nls_codepage);
927                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
928                 name_len2 *= 2; /* convert to bytes */
929         } else {                /* BB improve the check for buffer overruns BB */
930                 name_len = strnlen(fromName, 530);
931                 name_len++;     /* trailing null */
932                 strncpy(pSMB->OldFileName, fromName, name_len);
933                 name_len2 = strnlen(toName, 530);
934                 name_len2++;    /* trailing null */
935                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
936                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
937                 name_len2++;    /* trailing null */
938                 name_len2++;    /* signature byte */
939         }
940
941         pSMB->ByteCount = 1 /* 1st signature byte */  + name_len + name_len2;
942         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
943         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
944
945         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
946                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
947         if (rc) {
948                 cFYI(1, ("Send error in rename = %d", rc));
949         } 
950
951 #ifdef CONFIG_CIFS_STATS
952           else {
953                 atomic_inc(&tcon->num_renames);
954         }
955 #endif
956
957         if (pSMB)
958                 cifs_buf_release(pSMB);
959
960         if (rc == -EAGAIN)
961                 goto renameRetry;
962
963         return rc;
964 }
965
966 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
967                 int netfid, char * target_name, const struct nls_table * nls_codepage) 
968 {
969         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
970         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
971         struct set_file_rename * rename_info;
972         char *data_offset;
973         char dummy_string[30];
974         int rc = 0;
975         int bytes_returned = 0;
976         int len_of_str;
977
978         cFYI(1, ("Rename to File by handle"));
979         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
980                         (void **) &pSMBr);
981         if (rc)
982                 return rc;
983
984         pSMB->ParameterCount = 6;
985         pSMB->MaxSetupCount = 0;
986         pSMB->Reserved = 0;
987         pSMB->Flags = 0;
988         pSMB->Timeout = 0;
989         pSMB->Reserved2 = 0;
990         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req,
991                                 Fid) - 4;
992         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
993
994         data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
995         rename_info = (struct set_file_rename *) data_offset;
996         pSMB->MaxParameterCount = cpu_to_le16(2);
997         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
998         pSMB->SetupCount = 1;
999         pSMB->Reserved3 = 0;
1000         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1001         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount;
1002         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
1003         pSMB->TotalParameterCount = pSMB->ParameterCount;
1004         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
1005         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
1006         /* construct random name ".cifs_tmp<inodenum><mid>" */
1007         rename_info->overwrite = cpu_to_le32(1);
1008         rename_info->root_fid  = 0;
1009         /* unicode only call */
1010         if(target_name == NULL) {
1011                 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1012                 len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage);
1013         } else {
1014                 len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, 530, nls_codepage);
1015         }
1016         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1017         pSMB->DataCount = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1018         pSMB->ByteCount += pSMB->DataCount;
1019         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
1020         pSMB->TotalDataCount = pSMB->DataCount;
1021         pSMB->Fid = netfid;
1022         pSMB->InformationLevel =
1023                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1024         pSMB->Reserved4 = 0;
1025         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1026         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1027         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1028                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1029         if (rc) {
1030                 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1031         }
1032 #ifdef CONFIG_CIFS_STATS
1033           else {
1034                 atomic_inc(&pTcon->num_t2renames);
1035         }
1036 #endif
1037         if (pSMB)
1038                 cifs_buf_release(pSMB);
1039
1040         /* Note: On -EAGAIN error only caller can retry on handle based calls
1041                 since file handle passed in no longer valid */
1042
1043         return rc;
1044 }
1045
1046 int
1047 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
1048             const __u16 target_tid, const char *toName, const int flags,
1049             const struct nls_table *nls_codepage)
1050 {
1051         int rc = 0;
1052         COPY_REQ *pSMB = NULL;
1053         COPY_RSP *pSMBr = NULL;
1054         int bytes_returned;
1055         int name_len, name_len2;
1056
1057         cFYI(1, ("In CIFSSMBCopy"));
1058 copyRetry:
1059         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1060                         (void **) &pSMBr);
1061         if (rc)
1062                 return rc;
1063
1064         pSMB->BufferFormat = 0x04;
1065         pSMB->Tid2 = target_tid;
1066
1067         if(flags & COPY_TREE)
1068                 pSMB->Flags |= COPY_TREE;
1069         pSMB->Flags = cpu_to_le16(pSMB->Flags);
1070
1071         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1072                 name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, 
1073                                 fromName, 
1074                                 530 /* find define for this maxpathcomponent */,
1075                                 nls_codepage);
1076                 name_len++;     /* trailing null */
1077                 name_len *= 2;
1078                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1079                 /* protocol requires ASCII signature byte on Unicode string */
1080                 pSMB->OldFileName[name_len + 1] = 0x00;
1081                 name_len2 = cifs_strtoUCS((wchar_t *) & pSMB->
1082                                 OldFileName[name_len + 2], toName, 530,
1083                                 nls_codepage);
1084                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1085                 name_len2 *= 2; /* convert to bytes */
1086         } else {                /* BB improve the check for buffer overruns BB */
1087                 name_len = strnlen(fromName, 530);
1088                 name_len++;     /* trailing null */
1089                 strncpy(pSMB->OldFileName, fromName, name_len);
1090                 name_len2 = strnlen(toName, 530);
1091                 name_len2++;    /* trailing null */
1092                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1093                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1094                 name_len2++;    /* trailing null */
1095                 name_len2++;    /* signature byte */
1096         }
1097
1098         pSMB->ByteCount = 1 /* 1st signature byte */  + name_len + name_len2;
1099         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1100         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1101
1102         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1103                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1104         if (rc) {
1105                 cFYI(1, ("Send error in copy = %d with %d files copied",
1106                         rc, pSMBr->CopyCount));
1107         }
1108         if (pSMB)
1109                 cifs_buf_release(pSMB);
1110
1111         if (rc == -EAGAIN)
1112                 goto copyRetry;
1113
1114         return rc;
1115 }
1116
1117 int
1118 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1119                       const char *fromName, const char *toName,
1120                       const struct nls_table *nls_codepage)
1121 {
1122         TRANSACTION2_SPI_REQ *pSMB = NULL;
1123         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1124         char *data_offset;
1125         int name_len;
1126         int name_len_target;
1127         int rc = 0;
1128         int bytes_returned = 0;
1129
1130         cFYI(1, ("In Symlink Unix style"));
1131 createSymLinkRetry:
1132         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1133                       (void **) &pSMBr);
1134         if (rc)
1135                 return rc;
1136
1137         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1138                 name_len =
1139                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, 530
1140                                   /* find define for this maxpathcomponent */
1141                                   , nls_codepage);
1142                 name_len++;     /* trailing null */
1143                 name_len *= 2;
1144
1145         } else {                /* BB improve the check for buffer overruns BB */
1146                 name_len = strnlen(fromName, 530);
1147                 name_len++;     /* trailing null */
1148                 strncpy(pSMB->FileName, fromName, name_len);
1149         }
1150         pSMB->ParameterCount = 6 + name_len;
1151         pSMB->MaxSetupCount = 0;
1152         pSMB->Reserved = 0;
1153         pSMB->Flags = 0;
1154         pSMB->Timeout = 0;
1155         pSMB->Reserved2 = 0;
1156         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
1157                                      InformationLevel) - 4;
1158         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
1159
1160         data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
1161         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1162                 name_len_target =
1163                     cifs_strtoUCS((wchar_t *) data_offset, toName, 530
1164                                   /* find define for this maxpathcomponent */
1165                                   , nls_codepage);
1166                 name_len_target++;      /* trailing null */
1167                 name_len_target *= 2;
1168         } else {                /* BB improve the check for buffer overruns BB */
1169                 name_len_target = strnlen(toName, 530);
1170                 name_len_target++;      /* trailing null */
1171                 strncpy(data_offset, toName, name_len_target);
1172         }
1173
1174         pSMB->DataCount = name_len_target;
1175         pSMB->MaxParameterCount = cpu_to_le16(2);
1176         /* BB find exact max on data count below from sess */
1177         pSMB->MaxDataCount = cpu_to_le16(1000);
1178         pSMB->SetupCount = 1;
1179         pSMB->Reserved3 = 0;
1180         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1181         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
1182         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
1183         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
1184         pSMB->TotalDataCount = pSMB->DataCount;
1185         pSMB->TotalParameterCount = pSMB->ParameterCount;
1186         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
1187         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
1188         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1189         pSMB->Reserved4 = 0;
1190         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1191         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1192         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1193                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1194         if (rc) {
1195                 cFYI(1,
1196                      ("Send error in SetPathInfo (create symlink) = %d",
1197                       rc));
1198         }
1199
1200         if (pSMB)
1201                 cifs_buf_release(pSMB);
1202
1203         if (rc == -EAGAIN)
1204                 goto createSymLinkRetry;
1205
1206         return rc;
1207 }
1208
1209 int
1210 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1211                        const char *fromName, const char *toName,
1212                        const struct nls_table *nls_codepage)
1213 {
1214         TRANSACTION2_SPI_REQ *pSMB = NULL;
1215         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1216         char *data_offset;
1217         int name_len;
1218         int name_len_target;
1219         int rc = 0;
1220         int bytes_returned = 0;
1221
1222         cFYI(1, ("In Create Hard link Unix style"));
1223 createHardLinkRetry:
1224         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1225                       (void **) &pSMBr);
1226         if (rc)
1227                 return rc;
1228
1229         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1230                 name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, 530
1231                                          /* find define for this maxpathcomponent */
1232                                          , nls_codepage);
1233                 name_len++;     /* trailing null */
1234                 name_len *= 2;
1235
1236         } else {                /* BB improve the check for buffer overruns BB */
1237                 name_len = strnlen(toName, 530);
1238                 name_len++;     /* trailing null */
1239                 strncpy(pSMB->FileName, toName, name_len);
1240         }
1241         pSMB->ParameterCount = 6 + name_len;
1242         pSMB->MaxSetupCount = 0;
1243         pSMB->Reserved = 0;
1244         pSMB->Flags = 0;
1245         pSMB->Timeout = 0;
1246         pSMB->Reserved2 = 0;
1247         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
1248                                      InformationLevel) - 4;
1249         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
1250
1251         data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
1252         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1253                 name_len_target =
1254                     cifs_strtoUCS((wchar_t *) data_offset, fromName, 530
1255                                   /* find define for this maxpathcomponent */
1256                                   , nls_codepage);
1257                 name_len_target++;      /* trailing null */
1258                 name_len_target *= 2;
1259         } else {                /* BB improve the check for buffer overruns BB */
1260                 name_len_target = strnlen(fromName, 530);
1261                 name_len_target++;      /* trailing null */
1262                 strncpy(data_offset, fromName, name_len_target);
1263         }
1264
1265         pSMB->DataCount = name_len_target;
1266         pSMB->MaxParameterCount = cpu_to_le16(2);
1267         /* BB find exact max on data count below from sess*/
1268         pSMB->MaxDataCount = cpu_to_le16(1000);
1269         pSMB->SetupCount = 1;
1270         pSMB->Reserved3 = 0;
1271         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1272         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
1273         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
1274         pSMB->TotalParameterCount = pSMB->ParameterCount;
1275         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
1276         pSMB->TotalDataCount = pSMB->DataCount;
1277         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
1278         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
1279         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1280         pSMB->Reserved4 = 0;
1281         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1282         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1283         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1284                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1285         if (rc) {
1286                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1287         }
1288
1289         if (pSMB)
1290                 cifs_buf_release(pSMB);
1291         if (rc == -EAGAIN)
1292                 goto createHardLinkRetry;
1293
1294         return rc;
1295 }
1296
1297 int
1298 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1299                    const char *fromName, const char *toName,
1300                    const struct nls_table *nls_codepage)
1301 {
1302         int rc = 0;
1303         NT_RENAME_REQ *pSMB = NULL;
1304         RENAME_RSP *pSMBr = NULL;
1305         int bytes_returned;
1306         int name_len, name_len2;
1307
1308         cFYI(1, ("In CIFSCreateHardLink"));
1309 winCreateHardLinkRetry:
1310
1311         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1312                       (void **) &pSMBr);
1313         if (rc)
1314                 return rc;
1315
1316         pSMB->SearchAttributes =
1317             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1318                         ATTR_DIRECTORY);
1319         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1320         pSMB->ClusterCount = 0;
1321
1322         pSMB->BufferFormat = 0x04;
1323
1324         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1325                 name_len =
1326                     cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
1327                                   /* find define for this maxpathcomponent */
1328                                   , nls_codepage);
1329                 name_len++;     /* trailing null */
1330                 name_len *= 2;
1331                 pSMB->OldFileName[name_len] = 0;        /* pad */
1332                 pSMB->OldFileName[name_len + 1] = 0x04; 
1333                 name_len2 =
1334                     cifs_strtoUCS((wchar_t *) & pSMB->
1335                                   OldFileName[name_len + 2], toName, 530,
1336                                   nls_codepage);
1337                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1338                 name_len2 *= 2; /* convert to bytes */
1339         } else {                /* BB improve the check for buffer overruns BB */
1340                 name_len = strnlen(fromName, 530);
1341                 name_len++;     /* trailing null */
1342                 strncpy(pSMB->OldFileName, fromName, name_len);
1343                 name_len2 = strnlen(toName, 530);
1344                 name_len2++;    /* trailing null */
1345                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
1346                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1347                 name_len2++;    /* trailing null */
1348                 name_len2++;    /* signature byte */
1349         }
1350
1351         pSMB->ByteCount = 1 /* string type byte */  + name_len + name_len2;
1352         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1353         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1354
1355         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1356                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1357         if (rc) {
1358                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1359         }
1360         if (pSMB)
1361                 cifs_buf_release(pSMB);
1362         if (rc == -EAGAIN)
1363                 goto winCreateHardLinkRetry;
1364
1365         return rc;
1366 }
1367
1368 int
1369 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1370                         const unsigned char *searchName,
1371                         char *symlinkinfo, const int buflen,
1372                         const struct nls_table *nls_codepage)
1373 {
1374 /* SMB_QUERY_FILE_UNIX_LINK */
1375         TRANSACTION2_QPI_REQ *pSMB = NULL;
1376         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1377         int rc = 0;
1378         int bytes_returned;
1379         int name_len;
1380
1381         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1382
1383 querySymLinkRetry:
1384         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1385                       (void **) &pSMBr);
1386         if (rc)
1387                 return rc;
1388
1389         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1390                 name_len =
1391                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
1392                                   /* find define for this maxpathcomponent */
1393                                   , nls_codepage);
1394                 name_len++;     /* trailing null */
1395                 name_len *= 2;
1396         } else {                /* BB improve the check for buffer overruns BB */
1397                 name_len = strnlen(searchName, 530);
1398                 name_len++;     /* trailing null */
1399                 strncpy(pSMB->FileName, searchName, name_len);
1400         }
1401
1402         pSMB->TotalParameterCount =
1403             2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1404         pSMB->TotalDataCount = 0;
1405         pSMB->MaxParameterCount = cpu_to_le16(2);
1406         /* BB find exact max data count below from sess structure BB */
1407         pSMB->MaxDataCount = cpu_to_le16(4000);
1408         pSMB->MaxSetupCount = 0;
1409         pSMB->Reserved = 0;
1410         pSMB->Flags = 0;
1411         pSMB->Timeout = 0;
1412         pSMB->Reserved2 = 0;
1413         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1414         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1415         pSMB->DataCount = 0;
1416         pSMB->DataOffset = 0;
1417         pSMB->SetupCount = 1;
1418         pSMB->Reserved3 = 0;
1419         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1420         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1421         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
1422         pSMB->ParameterCount = pSMB->TotalParameterCount;
1423         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1424         pSMB->Reserved4 = 0;
1425         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1426         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1427
1428         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1429                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1430         if (rc) {
1431                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1432         } else {                /* decode response */
1433                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
1434                 pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
1435                 if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
1436                 /* BB also check enough total bytes returned */
1437                         rc = -EIO;      /* bad smb */
1438                 else {
1439                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1440                                 name_len = UniStrnlen((wchar_t *) ((char *)
1441                                         &pSMBr->hdr.Protocol +pSMBr->DataOffset),
1442                                         min_t(const int, buflen,pSMBr->DataCount) / 2);
1443                                 cifs_strfromUCS_le(symlinkinfo,
1444                                         (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1445                                                 pSMBr->DataOffset),
1446                                         name_len, nls_codepage);
1447                         } else {
1448                                 strncpy(symlinkinfo,
1449                                         (char *) &pSMBr->hdr.Protocol + 
1450                                                 pSMBr->DataOffset,
1451                                         min_t(const int, buflen, pSMBr->DataCount));
1452                         }
1453                         symlinkinfo[buflen] = 0;
1454         /* just in case so calling code does not go off the end of buffer */
1455                 }
1456         }
1457         if (pSMB)
1458                 cifs_buf_release(pSMB);
1459         if (rc == -EAGAIN)
1460                 goto querySymLinkRetry;
1461         return rc;
1462 }
1463
1464
1465
1466 int
1467 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1468                         const unsigned char *searchName,
1469                         char *symlinkinfo, const int buflen,__u16 fid,
1470                         const struct nls_table *nls_codepage)
1471 {
1472         int rc = 0;
1473         int bytes_returned;
1474         int name_len;
1475         struct smb_com_transaction_ioctl_req * pSMB;
1476         struct smb_com_transaction_ioctl_rsp * pSMBr;
1477
1478         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1479         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1480                       (void **) &pSMBr);
1481         if (rc)
1482                 return rc;
1483
1484         pSMB->TotalParameterCount = 0 ;
1485         pSMB->TotalDataCount = 0;
1486         pSMB->MaxParameterCount = cpu_to_le32(2);
1487         /* BB find exact data count max from sess structure BB */
1488         pSMB->MaxDataCount = cpu_to_le32(4000);
1489         pSMB->MaxSetupCount = 4;
1490         pSMB->Reserved = 0;
1491         pSMB->ParameterOffset = 0;
1492         pSMB->DataCount = 0;
1493         pSMB->DataOffset = 0;
1494         pSMB->SetupCount = 4;
1495         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1496         pSMB->ParameterCount = pSMB->TotalParameterCount;
1497         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1498         pSMB->IsFsctl = 1; /* FSCTL */
1499         pSMB->IsRootFlag = 0;
1500         pSMB->Fid = fid; /* file handle always le */
1501         pSMB->ByteCount = 0;
1502
1503         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1504                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1505         if (rc) {
1506                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1507         } else {                /* decode response */
1508                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
1509                 pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
1510                 if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
1511                 /* BB also check enough total bytes returned */
1512                         rc = -EIO;      /* bad smb */
1513                 else {
1514                         if(pSMBr->DataCount && (pSMBr->DataCount < 2048)) {
1515                 /* could also validate reparse tag && better check name length */
1516                                 struct reparse_data * reparse_buf = (struct reparse_data *)
1517                                         ((char *)&pSMBr->hdr.Protocol + pSMBr->DataOffset);
1518                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1519                                         name_len = UniStrnlen((wchar_t *)
1520                                                         (reparse_buf->LinkNamesBuf + 
1521                                                         reparse_buf->TargetNameOffset),
1522                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
1523                                         cifs_strfromUCS_le(symlinkinfo,
1524                                                 (wchar_t *) (reparse_buf->LinkNamesBuf + 
1525                                                 reparse_buf->TargetNameOffset),
1526                                                 name_len, nls_codepage);
1527                                 } else { /* ASCII names */
1528                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
1529                                                 reparse_buf->TargetNameOffset, 
1530                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
1531                                 }
1532                         } else {
1533                                 rc = -EIO;
1534                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1535                         }
1536                         symlinkinfo[buflen] = 0; /* just in case so the caller
1537                                         does not go off the end of the buffer */
1538                         cFYI(1,("readlink result - %s ",symlinkinfo));
1539                 }
1540         }
1541         if (pSMB)
1542                 cifs_buf_release(pSMB);
1543
1544         /* Note: On -EAGAIN error only caller can retry on handle based calls
1545                 since file handle passed in no longer valid */
1546
1547         return rc;
1548 }
1549
1550 int
1551 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
1552                  const unsigned char *searchName,
1553                  FILE_ALL_INFO * pFindData,
1554                  const struct nls_table *nls_codepage)
1555 {
1556 /* level 263 SMB_QUERY_FILE_ALL_INFO */
1557         TRANSACTION2_QPI_REQ *pSMB = NULL;
1558         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1559         int rc = 0;
1560         int bytes_returned;
1561         int name_len;
1562
1563         cFYI(1, ("In QPathInfo path %s", searchName));
1564 QPathInfoRetry:
1565         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1566                       (void **) &pSMBr);
1567         if (rc)
1568                 return rc;
1569
1570         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1571                 name_len =
1572                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
1573                                   /* find define for this maxpathcomponent */
1574                                   , nls_codepage);
1575                 name_len++;     /* trailing null */
1576                 name_len *= 2;
1577         } else {                /* BB improve the check for buffer overruns BB */
1578                 name_len = strnlen(searchName, 530);
1579                 name_len++;     /* trailing null */
1580                 strncpy(pSMB->FileName, searchName, name_len);
1581         }
1582
1583         pSMB->TotalParameterCount = 2 /* level */  + 4 /* reserved */  +
1584             name_len /* includes null */ ;
1585         pSMB->TotalDataCount = 0;
1586         pSMB->MaxParameterCount = cpu_to_le16(2);
1587         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
1588         pSMB->MaxSetupCount = 0;
1589         pSMB->Reserved = 0;
1590         pSMB->Flags = 0;
1591         pSMB->Timeout = 0;
1592         pSMB->Reserved2 = 0;
1593         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1594         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1595         pSMB->DataCount = 0;
1596         pSMB->DataOffset = 0;
1597         pSMB->SetupCount = 1;
1598         pSMB->Reserved3 = 0;
1599         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1600         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1601         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
1602         pSMB->ParameterCount = pSMB->TotalParameterCount;
1603         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
1604         pSMB->Reserved4 = 0;
1605         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1606         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1607
1608         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1609                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1610         if (rc) {
1611                 cFYI(1, ("Send error in QPathInfo = %d", rc));
1612         } else {                /* decode response */
1613                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
1614                 /* BB also check enough total bytes returned */
1615                 /* BB we need to improve the validity checking
1616                 of these trans2 responses */
1617                 if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512)) 
1618                         rc = -EIO;      /* bad smb */
1619                 else if (pFindData){
1620                         memcpy((char *) pFindData,
1621                                (char *) &pSMBr->hdr.Protocol +
1622                                pSMBr->DataOffset, sizeof (FILE_ALL_INFO));
1623                 } else
1624                     rc = -ENOMEM;
1625         }
1626         if (pSMB)
1627                 cifs_buf_release(pSMB);
1628         if (rc == -EAGAIN)
1629                 goto QPathInfoRetry;
1630
1631         return rc;
1632 }
1633
1634 int
1635 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
1636                      const unsigned char *searchName,
1637                      FILE_UNIX_BASIC_INFO * pFindData,
1638                      const struct nls_table *nls_codepage)
1639 {
1640 /* SMB_QUERY_FILE_UNIX_BASIC */
1641         TRANSACTION2_QPI_REQ *pSMB = NULL;
1642         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1643         int rc = 0;
1644         int bytes_returned = 0;
1645         int name_len;
1646
1647         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
1648 UnixQPathInfoRetry:
1649         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1650                       (void **) &pSMBr);
1651         if (rc)
1652                 return rc;
1653
1654         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1655                 name_len =
1656                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
1657                                   /* find define for this maxpathcomponent */
1658                                   , nls_codepage);
1659                 name_len++;     /* trailing null */
1660                 name_len *= 2;
1661         } else {                /* BB improve the check for buffer overruns BB */
1662                 name_len = strnlen(searchName, 530);
1663                 name_len++;     /* trailing null */
1664                 strncpy(pSMB->FileName, searchName, name_len);
1665         }
1666
1667         pSMB->TotalParameterCount = 2 /* level */  + 4 /* reserved */  +
1668             name_len /* includes null */ ;
1669         pSMB->TotalDataCount = 0;
1670         pSMB->MaxParameterCount = cpu_to_le16(2);
1671         /* BB find exact max SMB PDU from sess structure BB */
1672         pSMB->MaxDataCount = cpu_to_le16(4000); 
1673         pSMB->MaxSetupCount = 0;
1674         pSMB->Reserved = 0;
1675         pSMB->Flags = 0;
1676         pSMB->Timeout = 0;
1677         pSMB->Reserved2 = 0;
1678         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1679         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1680         pSMB->DataCount = 0;
1681         pSMB->DataOffset = 0;
1682         pSMB->SetupCount = 1;
1683         pSMB->Reserved3 = 0;
1684         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1685         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1686         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
1687         pSMB->ParameterCount = pSMB->TotalParameterCount;
1688         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1689         pSMB->Reserved4 = 0;
1690         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1691         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1692
1693         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1694                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1695         if (rc) {
1696                 cFYI(1, ("Send error in QPathInfo = %d", rc));
1697         } else {                /* decode response */
1698                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
1699                 /* BB also check if enough total bytes returned */
1700                 if ((pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO)) || 
1701                         (pSMBr->DataOffset > 512) || 
1702                         (pSMBr->DataOffset < sizeof(struct smb_hdr))) {
1703                         cFYI(1,("UnixQPathinfo invalid data offset %d bytes returned %d",
1704                                         (int)pSMBr->DataOffset,bytes_returned));
1705                         rc = -EIO;      /* bad smb */
1706                 } else {
1707                         memcpy((char *) pFindData,
1708                                (char *) &pSMBr->hdr.Protocol +
1709                                pSMBr->DataOffset,
1710                                sizeof (FILE_UNIX_BASIC_INFO));
1711                 }
1712         }
1713         if (pSMB)
1714                 cifs_buf_release(pSMB);
1715         if (rc == -EAGAIN)
1716                 goto UnixQPathInfoRetry;
1717
1718         return rc;
1719 }
1720
1721 int
1722 CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
1723                const char *searchName, FILE_ALL_INFO * findData,
1724                const struct nls_table *nls_codepage)
1725 {
1726 /* level 257 SMB_ */
1727         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
1728         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
1729         int rc = 0;
1730         int bytes_returned;
1731         int name_len;
1732
1733         cFYI(1, ("In FindUnique"));
1734 findUniqueRetry:
1735         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1736                       (void **) &pSMBr);
1737         if (rc)
1738                 return rc;
1739
1740         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1741                 name_len =
1742                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
1743                                   /* find define for this maxpathcomponent */
1744                                   , nls_codepage);
1745                 name_len++;     /* trailing null */
1746                 name_len *= 2;
1747         } else {                /* BB improve the check for buffer overruns BB */
1748                 name_len = strnlen(searchName, 530);
1749                 name_len++;     /* trailing null */
1750                 strncpy(pSMB->FileName, searchName, name_len);
1751         }
1752
1753         pSMB->TotalParameterCount = 12 + name_len /* includes null */ ;
1754         pSMB->TotalDataCount = 0;       /* no EAs */
1755         pSMB->MaxParameterCount = cpu_to_le16(2);
1756         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
1757         pSMB->MaxSetupCount = 0;
1758         pSMB->Reserved = 0;
1759         pSMB->Flags = 0;
1760         pSMB->Timeout = 0;
1761         pSMB->Reserved2 = 0;
1762         pSMB->ParameterOffset = cpu_to_le16(
1763         offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
1764         pSMB->DataCount = 0;
1765         pSMB->DataOffset = 0;
1766         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
1767         pSMB->Reserved3 = 0;
1768         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
1769         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1770         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalDataCount);
1771         pSMB->ParameterCount = pSMB->TotalParameterCount;
1772         pSMB->SearchAttributes =
1773             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1774                         ATTR_DIRECTORY);
1775         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
1776         pSMB->SearchFlags = cpu_to_le16(1);
1777         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
1778         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
1779         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1780         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1781
1782         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1783                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1784
1785         if (rc) {
1786                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
1787         } else {                /* decode response */
1788
1789                 /* BB fill in */
1790         }
1791         if (pSMB)
1792                 cifs_buf_release(pSMB);
1793         if (rc == -EAGAIN)
1794                 goto findUniqueRetry;
1795
1796         return rc;
1797 }
1798
1799 int
1800 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
1801               const char *searchName, FILE_DIRECTORY_INFO * findData,
1802               T2_FFIRST_RSP_PARMS * findParms,
1803               const struct nls_table *nls_codepage, int *pUnicodeFlag,
1804               int *pUnixFlag)
1805 {
1806 /* level 257 SMB_ */
1807         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
1808         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
1809         char *response_data;
1810         int rc = 0;
1811         int bytes_returned;
1812         int name_len;
1813
1814         cFYI(1, ("In FindFirst"));
1815 findFirstRetry:
1816         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1817                       (void **) &pSMBr);
1818         if (rc)
1819                 return rc;
1820
1821         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1822                 name_len =
1823                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
1824                                   /* find define for this maxpathcomponent */
1825                                   , nls_codepage);
1826                 name_len++;     /* trailing null */
1827                 name_len *= 2;
1828         } else {                /* BB improve the check for buffer overruns BB */
1829                 name_len = strnlen(searchName, 530);
1830                 name_len++;     /* trailing null */
1831                 strncpy(pSMB->FileName, searchName, name_len);
1832         }
1833
1834         pSMB->TotalParameterCount = 12 + name_len /* includes null */ ;
1835         pSMB->TotalDataCount = 0;       /* no EAs */
1836         pSMB->MaxParameterCount = cpu_to_le16(10);
1837         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
1838                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1839         pSMB->MaxSetupCount = 0;
1840         pSMB->Reserved = 0;
1841         pSMB->Flags = 0;
1842         pSMB->Timeout = 0;
1843         pSMB->Reserved2 = 0;
1844         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1845         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
1846         pSMB->ParameterCount = pSMB->TotalParameterCount;
1847         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
1848         smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
1849         pSMB->DataCount = 0;
1850         pSMB->DataOffset = 0;
1851         pSMB->SetupCount = 1;   /* one byte no need to make endian neutral */
1852         pSMB->Reserved3 = 0;
1853         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
1854         pSMB->SearchAttributes =
1855             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1856                         ATTR_DIRECTORY);
1857         pSMB->SearchCount = cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO));       /* should this be shrunk even more ? */
1858         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
1859
1860         /* test for Unix extensions */
1861         if (tcon->ses->capabilities & CAP_UNIX) {
1862                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
1863                 *pUnixFlag = TRUE;
1864         } else {
1865                 pSMB->InformationLevel =
1866                     cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
1867                 *pUnixFlag = FALSE;
1868         }
1869         pSMB->SearchStorageType = 0;    /* BB what should we set this to? It is not clear if it matters BB */
1870         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1871         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1872
1873         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1874                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1875
1876         if (rc) {               /* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
1877                 cFYI(1, ("Error in FindFirst = %d", rc));
1878         } else {                /* decode response */
1879                 /* BB add safety checks for these memcpys */
1880                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
1881                         *pUnicodeFlag = TRUE;
1882                 else
1883                         *pUnicodeFlag = FALSE;
1884                 memcpy(findParms,
1885                        (char *) &pSMBr->hdr.Protocol +
1886                        le16_to_cpu(pSMBr->ParameterOffset),
1887                        sizeof (T2_FFIRST_RSP_PARMS));
1888                 /* search handle can stay LE and EAoffset not needed so not converted */
1889                 findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch);
1890                 findParms->LastNameOffset =
1891                     le16_to_cpu(findParms->LastNameOffset);
1892                 findParms->SearchCount = le16_to_cpu(findParms->SearchCount);
1893                 response_data =
1894                     (char *) &pSMBr->hdr.Protocol +
1895                     le16_to_cpu(pSMBr->DataOffset);
1896                 memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount));
1897         }
1898         if (pSMB)
1899                 cifs_buf_release(pSMB);
1900
1901         if (rc == -EAGAIN)
1902                 goto findFirstRetry;
1903
1904         return rc;
1905 }
1906
1907 int
1908 CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
1909                 FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms,
1910                 const __u16 searchHandle, char * resume_file_name, int name_len,
1911                 __u32 resume_key, int *pUnicodeFlag, int *pUnixFlag)
1912 {
1913 /* level 257 SMB_ */
1914         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
1915         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
1916         char *response_data;
1917         int rc = 0;
1918         int bytes_returned;
1919
1920         cFYI(1, ("In FindNext"));
1921
1922         if(resume_file_name == NULL) {
1923                 return -EIO;
1924         }
1925         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1926                       (void **) &pSMBr);
1927         if (rc)
1928                 return rc;
1929
1930         pSMB->TotalParameterCount = 14; /* includes 2 bytes of null string, converted to LE below */
1931         pSMB->TotalDataCount = 0;       /* no EAs */
1932         pSMB->MaxParameterCount = cpu_to_le16(8);
1933         pSMB->MaxDataCount =
1934             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1935         pSMB->MaxSetupCount = 0;
1936         pSMB->Reserved = 0;
1937         pSMB->Flags = 0;
1938         pSMB->Timeout = 0;
1939         pSMB->Reserved2 = 0;
1940         pSMB->ParameterOffset =  cpu_to_le16(offsetof(
1941         struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
1942         pSMB->DataCount = 0;
1943         pSMB->DataOffset = 0;
1944         pSMB->SetupCount = 1;
1945         pSMB->Reserved3 = 0;
1946         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
1947         pSMB->SearchHandle = searchHandle;      /* always kept as le */
1948         findParms->SearchCount = 0;     /* set to zero in case of error */
1949         pSMB->SearchCount =
1950             cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO));
1951         /* test for Unix extensions */
1952         if (tcon->ses->capabilities & CAP_UNIX) {
1953                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
1954                 *pUnixFlag = TRUE;
1955         } else {
1956                 pSMB->InformationLevel =
1957                     cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
1958                 *pUnixFlag = FALSE;
1959         }
1960         pSMB->ResumeKey = resume_key;
1961         pSMB->SearchFlags =
1962             cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
1963         /* BB add check to make sure we do not cross end of smb */
1964         if(name_len < CIFS_MAX_MSGSIZE) {
1965                 memcpy(pSMB->ResumeFileName, resume_file_name, name_len);
1966                 pSMB->ByteCount += name_len;
1967         }
1968         pSMB->TotalParameterCount += name_len;
1969         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
1970         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
1971         pSMB->ParameterCount = pSMB->TotalParameterCount;
1972         /* BB improve error handling here */
1973         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
1974         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
1975
1976         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1977                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1978
1979         if (rc) {
1980                 if (rc == -EBADF)
1981                         rc = 0; /* search probably was closed at end of search above */
1982                 else
1983                         cFYI(1, ("FindNext returned = %d", rc));
1984         } else {                /* decode response */
1985                 /* BB add safety checks for these memcpys */
1986                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
1987                         *pUnicodeFlag = TRUE;
1988                 else
1989                         *pUnicodeFlag = FALSE;
1990                 memcpy(findParms,
1991                        (char *) &pSMBr->hdr.Protocol +
1992                        le16_to_cpu(pSMBr->ParameterOffset),
1993                        sizeof (T2_FNEXT_RSP_PARMS));
1994                 findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch);
1995                 findParms->LastNameOffset =
1996                     le16_to_cpu(findParms->LastNameOffset);
1997                 findParms->SearchCount = le16_to_cpu(findParms->SearchCount);
1998                 response_data =
1999                     (char *) &pSMBr->hdr.Protocol +
2000                     le16_to_cpu(pSMBr->DataOffset);
2001                 memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount));
2002         }
2003         if (pSMB)
2004                 cifs_buf_release(pSMB);
2005
2006         /* Note: On -EAGAIN error only caller can retry on handle based calls
2007                 since file handle passed in no longer valid */
2008
2009         return rc;
2010 }
2011
2012 int
2013 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2014 {
2015         int rc = 0;
2016         FINDCLOSE_REQ *pSMB = NULL;
2017         CLOSE_RSP *pSMBr = NULL;
2018         int bytes_returned;
2019
2020         cFYI(1, ("In CIFSSMBFindClose"));
2021         rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB,
2022                       (void **) &pSMBr);
2023         /* no sense returning error if session restarted
2024                 file handle has been closed */
2025         if(rc == -EAGAIN)
2026                 return 0;
2027         if (rc)
2028                 return rc;
2029
2030         pSMB->FileID = searchHandle;
2031         pSMB->ByteCount = 0;
2032         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2033                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2034         if (rc) {
2035                 cERROR(1, ("Send error in FindClose = %d", rc));
2036         }
2037         if (pSMB)
2038                 cifs_buf_release(pSMB);
2039
2040         /* Since session is dead, search handle closed on server already */
2041         if (rc == -EAGAIN)
2042                 rc = 0;
2043
2044         return rc;
2045 }
2046
2047 int
2048 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2049                 const unsigned char *searchName,
2050                 unsigned char **targetUNCs,
2051                 unsigned int *number_of_UNC_in_array,
2052                 const struct nls_table *nls_codepage)
2053 {
2054 /* TRANS2_GET_DFS_REFERRAL */
2055         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2056         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2057         struct dfs_referral_level_3 * referrals = NULL;
2058         int rc = 0;
2059         int bytes_returned;
2060         int name_len;
2061         unsigned int i;
2062         char * temp;
2063         *number_of_UNC_in_array = 0;
2064         *targetUNCs = NULL;
2065
2066         cFYI(1, ("In GetDFSRefer the path %s", searchName));
2067         if (ses == NULL)
2068                 return -ENODEV;
2069 getDFSRetry:
2070         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2071                       (void **) &pSMBr);
2072         if (rc)
2073                 return rc;
2074
2075         pSMB->hdr.Tid = ses->ipc_tid;
2076         pSMB->hdr.Uid = ses->Suid;
2077         if (ses->capabilities & CAP_STATUS32) {
2078                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2079         }
2080         if (ses->capabilities & CAP_DFS) {
2081                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2082         }
2083
2084         if (ses->capabilities & CAP_UNICODE) {
2085                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2086                 name_len =
2087                     cifs_strtoUCS((wchar_t *) pSMB->RequestFileName,
2088                                   searchName, 530
2089                                   /* find define for this maxpathcomponent */
2090                                   , nls_codepage);
2091                 name_len++;     /* trailing null */
2092                 name_len *= 2;
2093         } else {                /* BB improve the check for buffer overruns BB */
2094                 name_len = strnlen(searchName, 530);
2095                 name_len++;     /* trailing null */
2096                 strncpy(pSMB->RequestFileName, searchName, name_len);
2097         }
2098
2099         pSMB->ParameterCount = 2 /* level */  + name_len /*includes null */ ;
2100         pSMB->TotalDataCount = 0;
2101         pSMB->DataCount = 0;
2102         pSMB->DataOffset = 0;
2103         pSMB->MaxParameterCount = 0;
2104         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2105         pSMB->MaxSetupCount = 0;
2106         pSMB->Reserved = 0;
2107         pSMB->Flags = 0;
2108         pSMB->Timeout = 0;
2109         pSMB->Reserved2 = 0;
2110         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2111         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2112         pSMB->SetupCount = 1;
2113         pSMB->Reserved3 = 0;
2114         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2115         pSMB->ByteCount = pSMB->ParameterCount + 3 /* pad */ ;
2116         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2117         pSMB->TotalParameterCount = pSMB->ParameterCount;
2118         pSMB->MaxReferralLevel = cpu_to_le16(3);
2119         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2120         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2121
2122         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2123                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2124         if (rc) {
2125                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2126         } else {                /* decode response */
2127 /* BB Add logic to parse referrals here */
2128                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
2129                 pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
2130                 cFYI(1,
2131                      ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
2132                       pSMBr->ByteCount, pSMBr->DataOffset));
2133                 if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512))       /* BB also check enough total bytes returned */
2134                         rc = -EIO;      /* bad smb */
2135                 else {
2136                         referrals = 
2137                             (struct dfs_referral_level_3 *) 
2138                                         (8 /* sizeof start of data block */ +
2139                                         pSMBr->DataOffset +
2140                                         (char *) &pSMBr->hdr.Protocol); 
2141                         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));
2142                         /* BB This field is actually two bytes in from start of
2143                            data block so we could do safety check that DataBlock
2144                            begins at address of pSMBr->NumberOfReferrals */
2145                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2146
2147                         /* BB Fix below so can return more than one referral */
2148                         if(*number_of_UNC_in_array > 1)
2149                                 *number_of_UNC_in_array = 1;
2150
2151                         /* get the length of the strings describing refs */
2152                         name_len = 0;
2153                         for(i=0;i<*number_of_UNC_in_array;i++) {
2154                                 /* make sure that DfsPathOffset not past end */
2155                                 referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset);
2156                                 if(referrals->DfsPathOffset > pSMBr->DataCount) {
2157                                         /* if invalid referral, stop here and do 
2158                                         not try to copy any more */
2159                                         *number_of_UNC_in_array = i;
2160                                         break;
2161                                 } 
2162                                 temp = ((char *)referrals) + referrals->DfsPathOffset;
2163
2164                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2165                                         name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount);
2166                                 } else {
2167                                         name_len += strnlen(temp,pSMBr->DataCount);
2168                                 }
2169                                 referrals++;
2170                                 /* BB add check that referral pointer does not fall off end PDU */
2171                                 
2172                         }
2173                         /* BB add check for name_len bigger than bcc */
2174                         *targetUNCs = 
2175                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2176                         /* copy the ref strings */
2177                         referrals =  
2178                             (struct dfs_referral_level_3 *) 
2179                                         (8 /* sizeof data hdr */ +
2180                                         pSMBr->DataOffset + 
2181                                         (char *) &pSMBr->hdr.Protocol);
2182
2183                         for(i=0;i<*number_of_UNC_in_array;i++) {
2184                                 temp = ((char *)referrals) + referrals->DfsPathOffset;
2185                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2186                                         cifs_strfromUCS_le(*targetUNCs,
2187                                                 (wchar_t *) temp, name_len, nls_codepage);
2188                                 } else {
2189                                         strncpy(*targetUNCs,temp,name_len);
2190                                 }
2191                                 /*  BB update target_uncs pointers */
2192                                 referrals++;
2193                         }
2194                         temp = *targetUNCs;
2195                         temp[name_len] = 0;
2196                 }
2197
2198         }
2199         if (pSMB)
2200                 cifs_buf_release(pSMB);
2201
2202         if (rc == -EAGAIN)
2203                 goto getDFSRetry;
2204
2205         return rc;
2206 }
2207
2208 int
2209 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
2210                struct kstatfs *FSData, const struct nls_table *nls_codepage)
2211 {
2212 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
2213         TRANSACTION2_QFSI_REQ *pSMB = NULL;
2214         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2215         FILE_SYSTEM_INFO *response_data;
2216         int rc = 0;
2217         int bytes_returned = 0;
2218
2219         cFYI(1, ("In QFSInfo"));
2220 QFSInfoRetry:
2221         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2222                       (void **) &pSMBr);
2223         if (rc)
2224                 return rc;
2225
2226         pSMB->TotalParameterCount = 2;  /* level */
2227         pSMB->TotalDataCount = 0;
2228         pSMB->MaxParameterCount = cpu_to_le16(2);
2229         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2230         pSMB->MaxSetupCount = 0;
2231         pSMB->Reserved = 0;
2232         pSMB->Flags = 0;
2233         pSMB->Timeout = 0;
2234         pSMB->Reserved2 = 0;
2235         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
2236         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
2237         pSMB->ParameterCount = pSMB->TotalParameterCount;
2238         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2239         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
2240         pSMB->DataCount = 0;
2241         pSMB->DataOffset = 0;
2242         pSMB->SetupCount = 1;
2243         pSMB->Reserved3 = 0;
2244         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
2245         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
2246         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2247         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2248
2249         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2250                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2251         if (rc) {
2252                 cERROR(1, ("Send error in QFSInfo = %d", rc));
2253         } else {                /* decode response */
2254                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
2255                 cFYI(1,
2256                      ("Decoding qfsinfo response.  BCC: %d  Offset %d",
2257                       pSMBr->ByteCount, pSMBr->DataOffset));
2258                 if ((pSMBr->ByteCount < 24) || (pSMBr->DataOffset > 512))       /* BB also check enough total bytes returned */
2259                         rc = -EIO;      /* bad smb */
2260                 else {
2261                         response_data =
2262                             (FILE_SYSTEM_INFO
2263                              *) (((char *) &pSMBr->hdr.Protocol) +
2264                                  pSMBr->DataOffset);
2265                         FSData->f_bsize =
2266                             le32_to_cpu(response_data->BytesPerSector) *
2267                             le32_to_cpu(response_data->
2268                                         SectorsPerAllocationUnit);
2269                         FSData->f_blocks =
2270                             le64_to_cpu(response_data->TotalAllocationUnits);
2271                         FSData->f_bfree = FSData->f_bavail =
2272                             le64_to_cpu(response_data->FreeAllocationUnits);
2273                         cFYI(1,
2274                              ("Blocks: %lld  Free: %lld Block size %ld",
2275                               (unsigned long long)FSData->f_blocks,
2276                               (unsigned long long)FSData->f_bfree,
2277                               FSData->f_bsize));
2278                 }
2279         }
2280         if (pSMB)
2281                 cifs_buf_release(pSMB);
2282
2283         if (rc == -EAGAIN)
2284                 goto QFSInfoRetry;
2285
2286         return rc;
2287 }
2288
2289 int
2290 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon,
2291                         const struct nls_table *nls_codepage)
2292 {
2293 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
2294         TRANSACTION2_QFSI_REQ *pSMB = NULL;
2295         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2296         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
2297         int rc = 0;
2298         int bytes_returned = 0;
2299
2300         cFYI(1, ("In QFSAttributeInfo"));
2301 QFSAttributeRetry:
2302         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2303                       (void **) &pSMBr);
2304         if (rc)
2305                 return rc;
2306
2307         pSMB->TotalParameterCount = 2;  /* level */
2308         pSMB->TotalDataCount = 0;
2309         pSMB->MaxParameterCount = cpu_to_le16(2);
2310         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2311         pSMB->MaxSetupCount = 0;
2312         pSMB->Reserved = 0;
2313         pSMB->Flags = 0;
2314         pSMB->Timeout = 0;
2315         pSMB->Reserved2 = 0;
2316         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
2317         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
2318         pSMB->ParameterCount = pSMB->TotalParameterCount;
2319         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2320         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
2321         pSMB->DataCount = 0;
2322         pSMB->DataOffset = 0;
2323         pSMB->SetupCount = 1;
2324         pSMB->Reserved3 = 0;
2325         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
2326         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
2327         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2328         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2329
2330         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2331                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2332         if (rc) {
2333                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
2334         } else {                /* decode response */
2335                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
2336                 if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) {     /* BB also check enough bytes returned */
2337                         rc = -EIO;      /* bad smb */
2338                 } else {
2339                         response_data =
2340                             (FILE_SYSTEM_ATTRIBUTE_INFO
2341                              *) (((char *) &pSMBr->hdr.Protocol) +
2342                                  pSMBr->DataOffset);
2343                         response_data->Attributes = le32_to_cpu(response_data->Attributes);
2344                         response_data->MaxPathNameComponentLength = 
2345                                 le32_to_cpu(response_data->MaxPathNameComponentLength);
2346                         response_data->FileSystemNameLen = 
2347                                 le32_to_cpu(response_data->FileSystemNameLen);
2348                         memcpy(&tcon->fsAttrInfo, response_data,
2349                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
2350                 }
2351         }
2352         if (pSMB)
2353                 cifs_buf_release(pSMB);
2354
2355         if (rc == -EAGAIN)
2356                 goto QFSAttributeRetry;
2357
2358         return rc;
2359 }
2360
2361 int
2362 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
2363                      const struct nls_table *nls_codepage)
2364 {
2365 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
2366         TRANSACTION2_QFSI_REQ *pSMB = NULL;
2367         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2368         FILE_SYSTEM_DEVICE_INFO *response_data;
2369         int rc = 0;
2370         int bytes_returned = 0;
2371
2372         cFYI(1, ("In QFSDeviceInfo"));
2373 QFSDeviceRetry:
2374         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2375                       (void **) &pSMBr);
2376         if (rc)
2377                 return rc;
2378
2379         pSMB->TotalParameterCount = 2;  /* level */
2380         pSMB->TotalDataCount = 0;
2381         pSMB->MaxParameterCount = cpu_to_le16(2);
2382         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2383         pSMB->MaxSetupCount = 0;
2384         pSMB->Reserved = 0;
2385         pSMB->Flags = 0;
2386         pSMB->Timeout = 0;
2387         pSMB->Reserved2 = 0;
2388         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
2389         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
2390         pSMB->ParameterCount = pSMB->TotalParameterCount;
2391         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2392         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
2393
2394         pSMB->DataCount = 0;
2395         pSMB->DataOffset = 0;
2396         pSMB->SetupCount = 1;
2397         pSMB->Reserved3 = 0;
2398         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
2399         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
2400         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2401         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2402
2403         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2404                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2405         if (rc) {
2406                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
2407         } else {                /* decode response */
2408                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
2409                 if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO))
2410                  || (pSMBr->DataOffset > 512))
2411                         rc = -EIO;      /* bad smb */
2412                 else {
2413                         response_data =
2414                             (FILE_SYSTEM_DEVICE_INFO
2415                              *) (((char *) &pSMBr->hdr.Protocol) +
2416                                  pSMBr->DataOffset);
2417                         response_data->DeviceType = 
2418                                 le32_to_cpu(response_data->DeviceType);
2419                         response_data->DeviceCharacteristics = 
2420                                 le32_to_cpu(response_data->DeviceCharacteristics);
2421                         memcpy(&tcon->fsDevInfo, response_data,
2422                                sizeof (FILE_SYSTEM_DEVICE_INFO));
2423                 }
2424         }
2425         if (pSMB)
2426                 cifs_buf_release(pSMB);
2427
2428         if (rc == -EAGAIN)
2429                 goto QFSDeviceRetry;
2430
2431         return rc;
2432 }
2433
2434 int
2435 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
2436                    const struct nls_table *nls_codepage)
2437 {
2438 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
2439         TRANSACTION2_QFSI_REQ *pSMB = NULL;
2440         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
2441         FILE_SYSTEM_UNIX_INFO *response_data;
2442         int rc = 0;
2443         int bytes_returned = 0;
2444
2445         cFYI(1, ("In QFSUnixInfo"));
2446 QFSUnixRetry:
2447         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2448                       (void **) &pSMBr);
2449         if (rc)
2450                 return rc;
2451
2452         pSMB->ParameterCount = 2;       /* level */
2453         pSMB->TotalDataCount = 0;
2454         pSMB->DataCount = 0;
2455         pSMB->DataOffset = 0;
2456         pSMB->MaxParameterCount = cpu_to_le16(2);
2457         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
2458         pSMB->MaxSetupCount = 0;
2459         pSMB->Reserved = 0;
2460         pSMB->Flags = 0;
2461         pSMB->Timeout = 0;
2462         pSMB->Reserved2 = 0;
2463         pSMB->ByteCount = pSMB->ParameterCount + 1 /* pad */ ;
2464         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2465         pSMB->TotalParameterCount = pSMB->ParameterCount;
2466         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
2467         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
2468         pSMB->SetupCount = 1;
2469         pSMB->Reserved3 = 0;
2470         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
2471         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
2472         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2473         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2474
2475         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2476                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2477         if (rc) {
2478                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
2479         } else {                /* decode response */
2480                 pSMBr->DataOffset = cpu_to_le16(pSMBr->DataOffset);
2481                 if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) {
2482                         rc = -EIO;      /* bad smb */
2483                 } else {
2484                         response_data =
2485                             (FILE_SYSTEM_UNIX_INFO
2486                              *) (((char *) &pSMBr->hdr.Protocol) +
2487                                  pSMBr->DataOffset);
2488                         response_data->MajorVersionNumber =
2489                                 le16_to_cpu(response_data->MajorVersionNumber);
2490                         response_data->MinorVersionNumber =
2491                                 le16_to_cpu(response_data->MinorVersionNumber);
2492                         response_data->Capability =
2493                                 le64_to_cpu(response_data->Capability);
2494                         memcpy(&tcon->fsUnixInfo, response_data,
2495                                sizeof (FILE_SYSTEM_UNIX_INFO));
2496                 }
2497         }
2498         if (pSMB)
2499                 cifs_buf_release(pSMB);
2500
2501         if (rc == -EAGAIN)
2502                 goto QFSUnixRetry;
2503
2504
2505         return rc;
2506 }
2507
2508 /* We can not use write of zero bytes trick to 
2509    set file size due to need for large file support.  Also note that 
2510    this SetPathInfo is preferred to SetFileInfo based method in next 
2511    routine which is only needed to work around a sharing violation bug
2512    in Samba which this routine can run into */
2513
2514 int
2515 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
2516               __u64 size, int SetAllocation, const struct nls_table *nls_codepage)
2517 {
2518         struct smb_com_transaction2_spi_req *pSMB = NULL;
2519         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2520         struct file_end_of_file_info *parm_data;
2521         int name_len;
2522         int rc = 0;
2523         int bytes_returned = 0;
2524
2525         cFYI(1, ("In SetEOF"));
2526 SetEOFRetry:
2527         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2528                       (void **) &pSMBr);
2529         if (rc)
2530                 return rc;
2531
2532         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2533                 name_len =
2534                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
2535                                   /* find define for this maxpathcomponent */
2536                                   , nls_codepage);
2537                 name_len++;     /* trailing null */
2538                 name_len *= 2;
2539         } else {                /* BB improve the check for buffer overruns BB */
2540                 name_len = strnlen(fileName, 530);
2541                 name_len++;     /* trailing null */
2542                 strncpy(pSMB->FileName, fileName, name_len);
2543         }
2544         pSMB->ParameterCount = 6 + name_len;
2545         pSMB->DataCount = sizeof (struct file_end_of_file_info);
2546         pSMB->MaxParameterCount = cpu_to_le16(2);
2547         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2548         pSMB->MaxSetupCount = 0;
2549         pSMB->Reserved = 0;
2550         pSMB->Flags = 0;
2551         pSMB->Timeout = 0;
2552         pSMB->Reserved2 = 0;
2553         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
2554                                      InformationLevel) - 4;
2555         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
2556         if(SetAllocation) {
2557                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
2558                     pSMB->InformationLevel =
2559                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
2560                 else
2561                     pSMB->InformationLevel =
2562                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
2563         } else /* Set File Size */  {    
2564             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
2565                     pSMB->InformationLevel =
2566                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
2567             else
2568                     pSMB->InformationLevel =
2569                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
2570         }
2571
2572         parm_data =
2573             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
2574                                        pSMB->DataOffset);
2575         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
2576         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
2577         pSMB->SetupCount = 1;
2578         pSMB->Reserved3 = 0;
2579         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2580         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
2581         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
2582         pSMB->TotalDataCount = pSMB->DataCount;
2583         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2584         pSMB->TotalParameterCount = pSMB->ParameterCount;
2585         pSMB->Reserved4 = 0;
2586         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2587         parm_data->FileSize = cpu_to_le64(size);
2588         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2589         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2590                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2591         if (rc) {
2592                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
2593         }
2594
2595         if (pSMB)
2596                 cifs_buf_release(pSMB);
2597
2598         if (rc == -EAGAIN)
2599                 goto SetEOFRetry;
2600
2601         return rc;
2602 }
2603
2604 int
2605 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
2606                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
2607 {
2608         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
2609         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2610         char *data_offset;
2611         struct file_end_of_file_info *parm_data;
2612         int rc = 0;
2613         int bytes_returned = 0;
2614         __u32 tmp;
2615
2616         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
2617                         (long long)size));
2618         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2619                       (void **) &pSMBr);
2620         if (rc)
2621                 return rc;
2622
2623         tmp = cpu_to_le32(pid_of_opener);  /* override pid of current process
2624                                          so network fid will be valid */
2625         pSMB->hdr.Pid = tmp & 0xFFFF;
2626         tmp >>= 16;
2627         pSMB->hdr.PidHigh = tmp & 0xFFFF;
2628     
2629         pSMB->ParameterCount = 6;
2630         pSMB->MaxSetupCount = 0;
2631         pSMB->Reserved = 0;
2632         pSMB->Flags = 0;
2633         pSMB->Timeout = 0;
2634         pSMB->Reserved2 = 0;
2635         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req,
2636                                      Fid) - 4;
2637         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
2638
2639         data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;        
2640
2641         pSMB->DataCount = sizeof(struct file_end_of_file_info);
2642         pSMB->MaxParameterCount = cpu_to_le16(2);
2643         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2644         pSMB->SetupCount = 1;
2645         pSMB->Reserved3 = 0;
2646         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2647         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
2648         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
2649         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2650         pSMB->TotalDataCount = pSMB->DataCount;
2651         pSMB->TotalParameterCount = pSMB->ParameterCount;
2652         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
2653         parm_data =
2654                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
2655                         pSMB->DataOffset);
2656         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */
2657         parm_data->FileSize = cpu_to_le64(size);
2658         pSMB->Fid = fid;
2659         if(SetAllocation) {
2660                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
2661                         pSMB->InformationLevel =
2662                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
2663                 else
2664                         pSMB->InformationLevel =
2665                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
2666         } else /* Set File Size */  {    
2667             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
2668                     pSMB->InformationLevel =
2669                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
2670             else
2671                     pSMB->InformationLevel =
2672                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
2673         }
2674         pSMB->Reserved4 = 0;
2675         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2676         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2677         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2678                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2679         if (rc) {
2680                 cFYI(1,
2681                      ("Send error in SetFileInfo (SetFileSize) = %d",
2682                       rc));
2683         }
2684
2685         if (pSMB)
2686                 cifs_buf_release(pSMB);
2687
2688         /* Note: On -EAGAIN error only caller can retry on handle based calls 
2689                 since file handle passed in no longer valid */
2690
2691         return rc;
2692 }
2693
2694 int
2695 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
2696                 const FILE_BASIC_INFO * data, 
2697                 const struct nls_table *nls_codepage)
2698 {
2699         TRANSACTION2_SPI_REQ *pSMB = NULL;
2700         TRANSACTION2_SPI_RSP *pSMBr = NULL;
2701         int name_len;
2702         int rc = 0;
2703         int bytes_returned = 0;
2704         char *data_offset;
2705
2706         cFYI(1, ("In SetTimes"));
2707
2708 SetTimesRetry:
2709         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2710                       (void **) &pSMBr);
2711         if (rc)
2712                 return rc;
2713
2714         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2715                 name_len =
2716                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
2717                                   /* find define for this maxpathcomponent */
2718                                   , nls_codepage);
2719                 name_len++;     /* trailing null */
2720                 name_len *= 2;
2721         } else {                /* BB improve the check for buffer overruns BB */
2722                 name_len = strnlen(fileName, 530);
2723                 name_len++;     /* trailing null */
2724                 strncpy(pSMB->FileName, fileName, name_len);
2725         }
2726
2727         pSMB->ParameterCount = 6 + name_len;
2728         pSMB->DataCount = sizeof (FILE_BASIC_INFO);
2729         pSMB->MaxParameterCount = cpu_to_le16(2);
2730         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2731         pSMB->MaxSetupCount = 0;
2732         pSMB->Reserved = 0;
2733         pSMB->Flags = 0;
2734         pSMB->Timeout = 0;
2735         pSMB->Reserved2 = 0;
2736         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
2737                                      InformationLevel) - 4;
2738         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
2739         data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
2740         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
2741         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
2742         pSMB->SetupCount = 1;
2743         pSMB->Reserved3 = 0;
2744         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2745         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
2746
2747         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
2748         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2749         pSMB->TotalDataCount = pSMB->DataCount;
2750         pSMB->TotalParameterCount = pSMB->ParameterCount;
2751         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
2752                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
2753         else
2754                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
2755         pSMB->Reserved4 = 0;
2756         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2757         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
2758         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2759         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2760                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2761         if (rc) {
2762                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
2763         }
2764
2765         if (pSMB)
2766                 cifs_buf_release(pSMB);
2767
2768         if (rc == -EAGAIN)
2769                 goto SetTimesRetry;
2770
2771         return rc;
2772 }
2773
2774
2775 int
2776 CIFSSMBSetTimesLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
2777                 FILE_INFO_STANDARD * data, const struct nls_table *nls_codepage)
2778 {
2779         TRANSACTION2_SPI_REQ *pSMB = NULL;
2780         TRANSACTION2_SPI_RSP *pSMBr = NULL;
2781         int name_len;
2782         int rc = 0;
2783         int bytes_returned = 0;
2784         char *data_offset;
2785
2786         cFYI(1, ("In SetTimesLegacy"));
2787
2788 SetTimesRetryLegacy:
2789         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2790                       (void **) &pSMBr);
2791         if (rc)
2792                 return rc;
2793
2794         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2795                 name_len =
2796                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
2797                                   /* find define for this maxpathcomponent */
2798                                   , nls_codepage);
2799                 name_len++;     /* trailing null */
2800                 name_len *= 2;
2801         } else {                /* BB improve the check for buffer overruns BB */
2802                 name_len = strnlen(fileName, 530);
2803                 name_len++;     /* trailing null */
2804                 strncpy(pSMB->FileName, fileName, name_len);
2805         }
2806 /* BB fixme - we have to map to FILE_STANDARD_INFO (level 1 info
2807         in parent function, from the better and ususal FILE_BASIC_INFO */
2808         pSMB->ParameterCount = 6 + name_len;
2809         pSMB->DataCount = sizeof (FILE_INFO_STANDARD);
2810         pSMB->MaxParameterCount = cpu_to_le16(2);
2811         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2812         pSMB->MaxSetupCount = 0;
2813         pSMB->Reserved = 0;
2814         pSMB->Flags = 0;
2815         pSMB->Timeout = 0;
2816         pSMB->Reserved2 = 0;
2817         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
2818                                      InformationLevel) - 4;
2819         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
2820         data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
2821         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
2822         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
2823         pSMB->SetupCount = 1;
2824         pSMB->Reserved3 = 0;
2825         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2826         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
2827
2828         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
2829         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2830         pSMB->TotalDataCount = pSMB->DataCount;
2831         pSMB->TotalParameterCount = pSMB->ParameterCount;
2832         /* I doubt that passthrough levels apply to this old
2833         preNT info level */
2834 /*      if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
2835                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
2836         else*/
2837                 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
2838         pSMB->Reserved4 = 0;
2839         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2840         memcpy(data_offset, data, sizeof (FILE_INFO_STANDARD));
2841         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2842         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2843                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2844         if (rc) {
2845                 cFYI(1, ("SetPathInfo (times legacy) returned %d", rc));
2846         }
2847
2848         if (pSMB)
2849                 cifs_buf_release(pSMB);
2850
2851         if (rc == -EAGAIN)
2852                 goto SetTimesRetryLegacy;
2853
2854         return rc;
2855 }
2856
2857 int
2858 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
2859                     char *fileName, __u64 mode, __u64 uid, __u64 gid,
2860                     dev_t device, const struct nls_table *nls_codepage)
2861 {
2862         TRANSACTION2_SPI_REQ *pSMB = NULL;
2863         TRANSACTION2_SPI_RSP *pSMBr = NULL;
2864         int name_len;
2865         int rc = 0;
2866         int bytes_returned = 0;
2867         FILE_UNIX_BASIC_INFO *data_offset;
2868
2869         cFYI(1, ("In SetUID/GID/Mode"));
2870 setPermsRetry:
2871         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2872                       (void **) &pSMBr);
2873         if (rc)
2874                 return rc;
2875
2876         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2877                 name_len =
2878                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
2879                                   /* find define for this maxpathcomponent */
2880                                   , nls_codepage);
2881                 name_len++;     /* trailing null */
2882                 name_len *= 2;
2883         } else {                /* BB improve the check for buffer overruns BB */
2884                 name_len = strnlen(fileName, 530);
2885                 name_len++;     /* trailing null */
2886                 strncpy(pSMB->FileName, fileName, name_len);
2887         }
2888
2889         pSMB->ParameterCount = 6 + name_len;
2890         pSMB->DataCount = sizeof (FILE_UNIX_BASIC_INFO);
2891         pSMB->MaxParameterCount = cpu_to_le16(2);
2892         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
2893         pSMB->MaxSetupCount = 0;
2894         pSMB->Reserved = 0;
2895         pSMB->Flags = 0;
2896         pSMB->Timeout = 0;
2897         pSMB->Reserved2 = 0;
2898         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
2899                                      InformationLevel) - 4;
2900         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
2901         data_offset =
2902             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
2903                                       pSMB->DataOffset);
2904         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
2905         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
2906         pSMB->SetupCount = 1;
2907         pSMB->Reserved3 = 0;
2908         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2909         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
2910         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
2911         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
2912         pSMB->TotalParameterCount = pSMB->ParameterCount;
2913         pSMB->TotalDataCount = pSMB->DataCount;
2914         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
2915         pSMB->Reserved4 = 0;
2916         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2917         data_offset->Uid = cpu_to_le64(uid);
2918         data_offset->Gid = cpu_to_le64(gid);
2919         /* better to leave device as zero when it is  */
2920         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
2921         data_offset->DevMinor = cpu_to_le64(MINOR(device));
2922         data_offset->Permissions = cpu_to_le64(mode);
2923     
2924         if(S_ISREG(mode))
2925                 data_offset->Type = cpu_to_le32(UNIX_FILE);
2926         else if(S_ISDIR(mode))
2927                 data_offset->Type = cpu_to_le32(UNIX_DIR);
2928         else if(S_ISLNK(mode))
2929                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
2930         else if(S_ISCHR(mode))
2931                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
2932         else if(S_ISBLK(mode))
2933                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
2934         else if(S_ISFIFO(mode))
2935                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
2936         else if(S_ISSOCK(mode))
2937                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
2938
2939
2940         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
2941         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2942                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2943         if (rc) {
2944                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
2945         }
2946
2947         if (pSMB)
2948                 cifs_buf_release(pSMB);
2949         if (rc == -EAGAIN)
2950                 goto setPermsRetry;
2951         return rc;
2952 }
2953
2954 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
2955                         const int notify_subdirs, const __u16 netfid,
2956                         __u32 filter, const struct nls_table *nls_codepage)
2957 {
2958         int rc = 0;
2959         struct smb_com_transaction_change_notify_req * pSMB = NULL;
2960         struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
2961         int bytes_returned;
2962
2963         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
2964         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2965                       (void **) &pSMBr);
2966         if (rc)
2967                 return rc;
2968
2969         pSMB->TotalParameterCount = 0 ;
2970         pSMB->TotalDataCount = 0;
2971         pSMB->MaxParameterCount = cpu_to_le32(2);
2972         /* BB find exact data count max from sess structure BB */
2973         pSMB->MaxDataCount = 0; /* same in little endian or be */
2974         pSMB->MaxSetupCount = 4;
2975         pSMB->Reserved = 0;
2976         pSMB->ParameterOffset = 0;
2977         pSMB->DataCount = 0;
2978         pSMB->DataOffset = 0;
2979         pSMB->SetupCount = 4; /* single byte does not need le conversion */
2980         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
2981         pSMB->ParameterCount = pSMB->TotalParameterCount;
2982         if(notify_subdirs)
2983                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
2984         pSMB->Reserved2 = 0;
2985         pSMB->CompletionFilter = cpu_to_le32(filter);
2986         pSMB->Fid = netfid; /* file handle always le */
2987         pSMB->ByteCount = 0;
2988
2989         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
2990         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2991                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2992         if (rc) {
2993                 cFYI(1, ("Error in Notify = %d", rc));
2994         }
2995         if (pSMB)
2996                 cifs_buf_release(pSMB);
2997 /*              if (rc == -EAGAIN)
2998                         goto NotifyRetry; */
2999         return rc;      
3000 }
3001 #ifdef CONFIG_CIFS_XATTR
3002 ssize_t
3003 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3004                  const unsigned char *searchName,
3005                  char * EAData, size_t buf_size,
3006                  const struct nls_table *nls_codepage)
3007 {
3008                 /* BB assumes one setup word */
3009         TRANSACTION2_QPI_REQ *pSMB = NULL;
3010         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3011         int rc = 0;
3012         int bytes_returned;
3013         int name_len;
3014         struct fea * temp_fea;
3015         char * temp_ptr;
3016
3017         cFYI(1, ("In Query All EAs path %s", searchName));
3018 QAllEAsRetry:
3019         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3020                       (void **) &pSMBr);
3021         if (rc)
3022                 return rc;
3023
3024         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3025                 name_len =
3026                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
3027                                   /* find define for this maxpathcomponent */
3028                                   , nls_codepage);
3029                 name_len++;     /* trailing null */
3030                 name_len *= 2;
3031         } else {        /* BB improve the check for buffer overruns BB */
3032                 name_len = strnlen(searchName, 530);
3033                 name_len++;     /* trailing null */
3034                 strncpy(pSMB->FileName, searchName, name_len);
3035         }
3036
3037         pSMB->TotalParameterCount = 2 /* level */  + 4 /* reserved */  +
3038             name_len /* includes null */ ;
3039         pSMB->TotalDataCount = 0;
3040         pSMB->MaxParameterCount = cpu_to_le16(2);
3041         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3042         pSMB->MaxSetupCount = 0;
3043         pSMB->Reserved = 0;
3044         pSMB->Flags = 0;
3045         pSMB->Timeout = 0;
3046         pSMB->Reserved2 = 0;
3047         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3048         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3049         pSMB->DataCount = 0;
3050         pSMB->DataOffset = 0;
3051         pSMB->SetupCount = 1;
3052         pSMB->Reserved3 = 0;
3053         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3054         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
3055         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
3056         pSMB->ParameterCount = pSMB->TotalParameterCount;
3057         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3058         pSMB->Reserved4 = 0;
3059         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
3060         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
3061
3062         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3063                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3064         if (rc) {
3065                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
3066         } else {                /* decode response */
3067                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
3068                 /* BB also check enough total bytes returned */
3069                 /* BB we need to improve the validity checking
3070                 of these trans2 responses */
3071                 if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512)) 
3072                         rc = -EIO;      /* bad smb */
3073            /* else if (pFindData){
3074                         memcpy((char *) pFindData,
3075                                (char *) &pSMBr->hdr.Protocol +
3076                                pSMBr->DataOffset, kl);
3077                 }*/ else {
3078                         /* check that length of list is not more than bcc */
3079                         /* check that each entry does not go beyond length
3080                            of list */
3081                         /* check that each element of each entry does not
3082                            go beyond end of list */
3083                         struct fealist * ea_response_data;
3084                         rc = 0;
3085                         /* validate_trans2_offsets() */
3086                         /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/
3087                         ea_response_data = (struct fealist *)
3088                                 (((char *) &pSMBr->hdr.Protocol) +
3089                                 pSMBr->DataOffset);
3090                         ea_response_data->list_len = 
3091                                 cpu_to_le32(ea_response_data->list_len);
3092                         cFYI(1,("ea length %d",ea_response_data->list_len));
3093                         name_len = ea_response_data->list_len;
3094                         if(name_len <= 8) {
3095                         /* returned EA size zeroed at top of function */
3096                                 cFYI(1,("empty EA list returned from server"));
3097                         } else {
3098                                 /* account for ea list len */
3099                                 name_len -= 4;
3100                                 temp_fea = ea_response_data->list;
3101                                 temp_ptr = (char *)temp_fea;
3102                                 while(name_len > 0) {
3103                                         name_len -= 4;
3104                                         temp_ptr += 4;
3105                                         rc += temp_fea->name_len;
3106                                 /* account for prefix user. and trailing null */
3107                                         rc = rc + 5 + 1; 
3108                                         if(rc<buf_size) {
3109                                                 memcpy(EAData,"user.",5);
3110                                                 EAData+=5;
3111                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
3112                                                 EAData+=temp_fea->name_len;
3113                                                 /* null terminate name */
3114                                                 *EAData = 0;
3115                                                 EAData = EAData + 1;
3116                                         } else if(buf_size == 0) {
3117                                                 /* skip copy - calc size only */
3118                                         } else {
3119                                                 /* stop before overrun buffer */
3120                                                 rc = -ERANGE;
3121                                                 break;
3122                                         }
3123                                         name_len -= temp_fea->name_len;
3124                                         temp_ptr += temp_fea->name_len;
3125                                         /* account for trailing null */
3126                                         name_len--;
3127                                         temp_ptr++;
3128                                         temp_fea->value_len = cpu_to_le16(temp_fea->value_len);
3129                                         name_len -= temp_fea->value_len;
3130                                         temp_ptr += temp_fea->value_len;
3131                                         /* BB check that temp_ptr is still within smb BB*/
3132                                 /* no trailing null to account for in value len */
3133                                         /* go on to next EA */
3134                                         temp_fea = (struct fea *)temp_ptr;
3135                                 }
3136                         }
3137                 }
3138         }
3139         if (pSMB)
3140                 cifs_buf_release(pSMB);
3141         if (rc == -EAGAIN)
3142                 goto QAllEAsRetry;
3143
3144         return rc;
3145 }
3146
3147 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
3148                 const unsigned char * searchName,const unsigned char * ea_name,
3149                 unsigned char * ea_value, size_t buf_size, 
3150                 const struct nls_table *nls_codepage)
3151 {
3152         TRANSACTION2_QPI_REQ *pSMB = NULL;
3153         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3154         int rc = 0;
3155         int bytes_returned;
3156         int name_len;
3157         struct fea * temp_fea;
3158         char * temp_ptr;
3159
3160         cFYI(1, ("In Query EA path %s", searchName));
3161 QEARetry:
3162         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3163                       (void **) &pSMBr);
3164         if (rc)
3165                 return rc;
3166
3167         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3168                 name_len =
3169                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
3170                                   /* find define for this maxpathcomponent */
3171                                   , nls_codepage);
3172                 name_len++;     /* trailing null */
3173                 name_len *= 2;
3174         } else {        /* BB improve the check for buffer overruns BB */
3175                 name_len = strnlen(searchName, 530);
3176                 name_len++;     /* trailing null */
3177                 strncpy(pSMB->FileName, searchName, name_len);
3178         }
3179
3180         pSMB->TotalParameterCount = 2 /* level */  + 4 /* reserved */  +
3181             name_len /* includes null */ ;
3182         pSMB->TotalDataCount = 0;
3183         pSMB->MaxParameterCount = cpu_to_le16(2);
3184         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3185         pSMB->MaxSetupCount = 0;
3186         pSMB->Reserved = 0;
3187         pSMB->Flags = 0;
3188         pSMB->Timeout = 0;
3189         pSMB->Reserved2 = 0;
3190         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3191         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3192         pSMB->DataCount = 0;
3193         pSMB->DataOffset = 0;
3194         pSMB->SetupCount = 1;
3195         pSMB->Reserved3 = 0;
3196         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3197         pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
3198         pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
3199         pSMB->ParameterCount = pSMB->TotalParameterCount;
3200         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3201         pSMB->Reserved4 = 0;
3202         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
3203         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
3204
3205         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3206                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3207         if (rc) {
3208                 cFYI(1, ("Send error in Query EA = %d", rc));
3209         } else {                /* decode response */
3210                 pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
3211                 /* BB also check enough total bytes returned */
3212                 /* BB we need to improve the validity checking
3213                 of these trans2 responses */
3214                 if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512)) 
3215                         rc = -EIO;      /* bad smb */
3216            /* else if (pFindData){
3217                         memcpy((char *) pFindData,
3218                                (char *) &pSMBr->hdr.Protocol +
3219                                pSMBr->DataOffset, kl);
3220                 }*/ else {
3221                         /* check that length of list is not more than bcc */
3222                         /* check that each entry does not go beyond length
3223                            of list */
3224                         /* check that each element of each entry does not
3225                            go beyond end of list */
3226                         struct fealist * ea_response_data;
3227                         rc = -ENOENT;
3228                         /* validate_trans2_offsets() */
3229                         /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/
3230                         ea_response_data = (struct fealist *)
3231                                 (((char *) &pSMBr->hdr.Protocol) +
3232                                 pSMBr->DataOffset);
3233                         ea_response_data->list_len = 
3234                                 cpu_to_le32(ea_response_data->list_len);
3235                         cFYI(1,("ea length %d",ea_response_data->list_len));
3236                         name_len = ea_response_data->list_len;
3237                         if(name_len <= 8) {
3238                         /* returned EA size zeroed at top of function */
3239                                 cFYI(1,("empty EA list returned from server"));
3240                         } else {
3241                                 /* account for ea list len */
3242                                 name_len -= 4;
3243                                 temp_fea = ea_response_data->list;
3244                                 temp_ptr = (char *)temp_fea;
3245                                 /* loop through checking if we have a matching
3246                                 name and then return the associated value */
3247                                 while(name_len > 0) {
3248                                         name_len -= 4;
3249                                         temp_ptr += 4;
3250                                         temp_fea->value_len = cpu_to_le16(temp_fea->value_len);
3251                                 /* BB validate that value_len falls within SMB, 
3252                                 even though maximum for name_len is 255 */ 
3253                                         if(memcmp(temp_fea->name,ea_name,
3254                                                   temp_fea->name_len) == 0) {
3255                                                 /* found a match */
3256                                                 rc = temp_fea->value_len;
3257                                 /* account for prefix user. and trailing null */
3258                                                 if(rc<=buf_size) {
3259                                                         memcpy(ea_value,
3260                                                                 temp_fea->name+temp_fea->name_len+1,
3261                                                                 rc);
3262                                                         /* ea values, unlike ea names,
3263                                                         are not null terminated */
3264                                                 } else if(buf_size == 0) {
3265                                                 /* skip copy - calc size only */
3266                                                 } else {
3267                                                         /* stop before overrun buffer */
3268                                                         rc = -ERANGE;
3269                                                 }
3270                                                 break;
3271                                         }
3272                                         name_len -= temp_fea->name_len;
3273                                         temp_ptr += temp_fea->name_len;
3274                                         /* account for trailing null */
3275                                         name_len--;
3276                                         temp_ptr++;
3277                                         name_len -= temp_fea->value_len;
3278                                         temp_ptr += temp_fea->value_len;
3279                                 /* no trailing null to account for in value len */
3280                                         /* go on to next EA */
3281                                         temp_fea = (struct fea *)temp_ptr;
3282                                 }
3283                         } 
3284                 }
3285         }
3286         if (pSMB)
3287                 cifs_buf_release(pSMB);
3288         if (rc == -EAGAIN)
3289                 goto QEARetry;
3290
3291         return rc;
3292 }
3293
3294 int
3295 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3296                 const char * ea_name, const void * ea_value, 
3297                 const __u16 ea_value_len, const struct nls_table *nls_codepage)
3298 {
3299         struct smb_com_transaction2_spi_req *pSMB = NULL;
3300         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3301         struct fealist *parm_data;
3302         int name_len;
3303         int rc = 0;
3304         int bytes_returned = 0;
3305
3306         cFYI(1, ("In SetEA"));
3307 SetEARetry:
3308         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3309                       (void **) &pSMBr);
3310         if (rc)
3311                 return rc;
3312
3313         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3314                 name_len =
3315                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
3316                                   /* find define for this maxpathcomponent */
3317                                   , nls_codepage);
3318                 name_len++;     /* trailing null */
3319                 name_len *= 2;
3320         } else {                /* BB improve the check for buffer overruns BB */
3321                 name_len = strnlen(fileName, 530);
3322                 name_len++;     /* trailing null */
3323                 strncpy(pSMB->FileName, fileName, name_len);
3324         }
3325
3326         pSMB->ParameterCount = 6 + name_len;
3327
3328         /* done calculating parms using name_len of file name,
3329         now use name_len to calculate length of ea name
3330         we are going to create in the inode xattrs */
3331         if(ea_name == NULL)
3332                 name_len = 0;
3333         else
3334                 name_len = strnlen(ea_name,255);
3335
3336         pSMB->DataCount = sizeof(*parm_data) + ea_value_len + name_len + 1;
3337         pSMB->MaxParameterCount = cpu_to_le16(2);
3338         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3339         pSMB->MaxSetupCount = 0;
3340         pSMB->Reserved = 0;
3341         pSMB->Flags = 0;
3342         pSMB->Timeout = 0;
3343         pSMB->Reserved2 = 0;
3344         pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
3345                                      InformationLevel) - 4;
3346         pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
3347         pSMB->InformationLevel =
3348                 cpu_to_le16(SMB_SET_FILE_EA);
3349
3350         parm_data =
3351                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
3352                                        pSMB->DataOffset);
3353         pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
3354         pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
3355         pSMB->SetupCount = 1;
3356         pSMB->Reserved3 = 0;
3357         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3358         pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
3359         pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
3360         parm_data->list_len = (__u32)(pSMB->DataCount);
3361         parm_data->list[0].EA_flags = 0;
3362         /* we checked above that name len is less than 255 */
3363         parm_data->list[0].name_len = (__u8)name_len;;
3364         /* EA names are always ASCII */
3365         strncpy(parm_data->list[0].name,ea_name,name_len);
3366         parm_data->list[0].name[name_len] = 0;
3367         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
3368         /* caller ensures that ea_value_len is less than 64K but
3369         we need to ensure that it fits within the smb */
3370
3371         /*BB add length check that it would fit in negotiated SMB buffer size BB */
3372         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
3373         if(ea_value_len)
3374                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
3375
3376         pSMB->TotalDataCount = pSMB->DataCount;
3377         pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
3378         pSMB->TotalParameterCount = pSMB->ParameterCount;
3379         pSMB->Reserved4 = 0;
3380         pSMB->hdr.smb_buf_length += pSMB->ByteCount;
3381         pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
3382         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3383                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3384         if (rc) {
3385                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
3386         }
3387
3388         if (pSMB)
3389                 cifs_buf_release(pSMB);
3390
3391         if (rc == -EAGAIN)
3392                 goto SetEARetry;
3393
3394         return rc;
3395 }
3396
3397 #endif