ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / cifs / file.c
1 /*
2  *   fs/cifs/file.c
3  *
4  *   vfs operations that deal with files
5  * 
6  *   Copyright (C) International Business Machines  Corp., 2002,2003
7  *   Author(s): Steve French (sfrench@us.ibm.com)
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 #include <linux/fs.h>
24 #include <linux/stat.h>
25 #include <linux/fcntl.h>
26 #include <linux/pagemap.h>
27 #include <linux/pagevec.h>
28 #include <linux/smp_lock.h>
29 #include <asm/div64.h>
30 #include "cifsfs.h"
31 #include "cifspdu.h"
32 #include "cifsglob.h"
33 #include "cifsproto.h"
34 #include "cifs_unicode.h"
35 #include "cifs_debug.h"
36 #include "cifs_fs_sb.h"
37
38 int
39 cifs_open(struct inode *inode, struct file *file)
40 {
41         int rc = -EACCES;
42         int xid, oplock;
43         struct cifs_sb_info *cifs_sb;
44         struct cifsTconInfo *pTcon;
45         struct cifsFileInfo *pCifsFile;
46         struct cifsInodeInfo *pCifsInode;
47         struct list_head * tmp;
48         char *full_path = NULL;
49         int desiredAccess = 0x20197;
50         int disposition;
51         __u16 netfid;
52         FILE_ALL_INFO * buf = NULL;
53
54         xid = GetXid();
55
56         cifs_sb = CIFS_SB(inode->i_sb);
57         pTcon = cifs_sb->tcon;
58
59         if (file->f_flags & O_CREAT) {
60                 /* search inode for this file and fill in file->private_data = */
61                 pCifsInode = CIFS_I(file->f_dentry->d_inode);
62                 read_lock(&GlobalSMBSeslock);
63                 list_for_each(tmp, &pCifsInode->openFileList) {            
64                         pCifsFile = list_entry(tmp,struct cifsFileInfo, flist);           
65                         if((pCifsFile->pfile == NULL)&& (pCifsFile->pid = current->pid)){
66                         /* mode set in cifs_create */
67                                 pCifsFile->pfile = file; /* needed for writepage */
68                                 file->private_data = pCifsFile;
69                                 break;
70                         }
71                 }
72                 read_unlock(&GlobalSMBSeslock);
73                 if(file->private_data != NULL) {
74                         rc = 0;
75                         FreeXid(xid);
76                         return rc;
77                 } else {
78                         if(file->f_flags & O_EXCL)
79                                 cERROR(1,("could not find file instance for new file %p ",file));
80                 }
81         }
82
83         full_path = build_path_from_dentry(file->f_dentry);
84
85         cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
86         if ((file->f_flags & O_ACCMODE) == O_RDONLY)
87                 desiredAccess = GENERIC_READ;
88         else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
89                 desiredAccess = GENERIC_WRITE;
90         else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
91                 /* GENERIC_ALL is too much permission to request */
92                 /* can cause unnecessary access denied on create */
93                 /* desiredAccess = GENERIC_ALL; */
94                 desiredAccess = GENERIC_READ | GENERIC_WRITE;
95         }
96
97 /*********************************************************************
98  *  open flag mapping table:
99  *  
100  *      POSIX Flag            CIFS Disposition
101  *      ----------            ---------------- 
102  *      O_CREAT               FILE_OPEN_IF
103  *      O_CREAT | O_EXCL      FILE_CREATE
104  *      O_CREAT | O_TRUNC     FILE_OVERWRITE_IF
105  *      O_TRUNC               FILE_OVERWRITE
106  *      none of the above     FILE_OPEN
107  *
108  *      Note that there is not a direct match between disposition
109  *      FILE_SUPERSEDE (ie create whether or not file exists although 
110  *      O_CREAT | O_TRUNC is similar but truncates the existing
111  *      file rather than creating a new file as FILE_SUPERSEDE does
112  *      (which uses the attributes / metadata passed in on open call)
113  *?
114  *?  O_SYNC is a reasonable match to CIFS writethrough flag  
115  *?  and the read write flags match reasonably.  O_LARGEFILE
116  *?  is irrelevant because largefile support is always used
117  *?  by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
118  *       O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
119  *********************************************************************/
120
121         if((file->f_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
122                 disposition = FILE_CREATE;
123         else if((file->f_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
124                 disposition = FILE_OVERWRITE_IF;
125         else if((file->f_flags & O_CREAT) == O_CREAT)
126                 disposition = FILE_OPEN_IF;
127         else
128                 disposition = FILE_OPEN;
129
130         if (oplockEnabled)
131                 oplock = REQ_OPLOCK;
132         else
133                 oplock = FALSE;
134
135         /* BB pass O_SYNC flag through on file attributes .. BB */
136
137         /* Also refresh inode by passing in file_info buf returned by SMBOpen 
138            and calling get_inode_info with returned buf (at least 
139            helps non-Unix server case */
140         buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
141         if(buf==0) {
142                 if (full_path)
143                         kfree(full_path);
144                 FreeXid(xid);
145                 return -ENOMEM;
146         }
147         rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
148                         CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls);
149         if (rc) {
150                 cFYI(1, ("cifs_open returned 0x%x ", rc));
151                 cFYI(1, ("oplock: %d ", oplock));       
152         } else {
153                 if(file->private_data)
154                         kfree(file->private_data);
155                 file->private_data =
156                         kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
157                 if (file->private_data) {
158                         memset(file->private_data, 0, sizeof(struct cifsFileInfo));
159                         pCifsFile = (struct cifsFileInfo *) file->private_data;
160                         pCifsFile->netfid = netfid;
161                         pCifsFile->pid = current->pid;
162                         init_MUTEX(&pCifsFile->fh_sem);
163                         pCifsFile->pfile = file; /* needed for writepage */
164                         pCifsFile->pInode = inode;
165                         pCifsFile->invalidHandle = FALSE;
166                         pCifsFile->closePend     = FALSE;
167                         write_lock(&file->f_owner.lock);
168                         write_lock(&GlobalSMBSeslock);
169                         list_add(&pCifsFile->tlist,&pTcon->openFileList);
170                         pCifsInode = CIFS_I(file->f_dentry->d_inode);
171                         if(pCifsInode) {
172                                 list_add(&pCifsFile->flist,&pCifsInode->openFileList);
173                                 write_unlock(&GlobalSMBSeslock);
174                                 write_unlock(&file->f_owner.lock);
175                                 if(pCifsInode->clientCanCacheRead) {
176                                         /* we have the inode open somewhere else
177                                            no need to discard cache data */
178                                 } else {
179                                         if(buf) {
180                                         /* BB need same check in cifs_create too? */
181
182                                         /* if not oplocked, invalidate inode pages if mtime 
183                                            or file size changed */
184                                                 struct timespec temp;
185                                                 temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
186                                                 if(timespec_equal(&file->f_dentry->d_inode->i_mtime,&temp) && 
187                                                         (file->f_dentry->d_inode->i_size == (loff_t)le64_to_cpu(buf->EndOfFile))) {
188                                                         cFYI(1,("inode unchanged on server"));
189                                                 } else {
190                                                         if(file->f_dentry->d_inode->i_mapping) {
191                                                         /* BB no need to lock inode until after invalidate*/
192                                                         /* since namei code should already have it locked?*/
193                                                                 filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
194                                                                 filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
195                                                         }
196                                                         cFYI(1,("invalidating remote inode since open detected it changed"));
197                                                         invalidate_remote_inode(file->f_dentry->d_inode);
198                                                 }
199                                         }
200                                 }
201                                 if (pTcon->ses->capabilities & CAP_UNIX)
202                                         rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
203                                                 full_path, inode->i_sb);
204                                 else
205                                         rc = cifs_get_inode_info(&file->f_dentry->d_inode,
206                                                 full_path, buf, inode->i_sb);
207
208                                 if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
209                                         pCifsInode->clientCanCacheAll = TRUE;
210                                         pCifsInode->clientCanCacheRead = TRUE;
211                                         cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
212                                 } else if((oplock & 0xF) == OPLOCK_READ)
213                                         pCifsInode->clientCanCacheRead = TRUE;
214                         } else {
215                                 write_unlock(&GlobalSMBSeslock);
216                                 write_unlock(&file->f_owner.lock);
217                         }
218                         if(oplock & CIFS_CREATE_ACTION) {           
219                                 /* time to set mode which we can not set earlier due
220                                  to problems creating new read-only files */
221                                 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)                
222                                         CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode,
223                                                 (__u64)-1, 
224                                                 (__u64)-1,
225                                                 0 /* dev */,
226                                                 cifs_sb->local_nls);
227                                 else {/* BB implement via Windows security descriptors */
228                         /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
229                         /* in the meantime could set r/o dos attribute when perms are eg:
230                                         mode & 0222 == 0 */
231                                 }
232                         }
233                 }
234         }
235
236         if (buf)
237                 kfree(buf);
238         if (full_path)
239                 kfree(full_path);
240         FreeXid(xid);
241         return rc;
242 }
243
244 /* Try to reaquire byte range locks that were released when session */
245 /* to server was lost */
246 static int cifs_relock_file(struct cifsFileInfo * cifsFile)
247 {
248         int rc = 0;
249
250 /* BB list all locks open on this file and relock */
251
252         return rc;
253 }
254
255 static int cifs_reopen_file(struct inode *inode, struct file *file)
256 {
257         int rc = -EACCES;
258         int xid, oplock;
259         struct cifs_sb_info *cifs_sb;
260         struct cifsTconInfo *pTcon;
261         struct cifsFileInfo *pCifsFile;
262         struct cifsInodeInfo *pCifsInode;
263         char *full_path = NULL;
264         int desiredAccess = 0x20197;
265         int disposition = FILE_OPEN;
266         __u16 netfid;
267         FILE_ALL_INFO * buf = NULL;
268
269         if(inode == NULL)
270                 return -EBADF;
271         if (file->private_data) {
272                 pCifsFile = (struct cifsFileInfo *) file->private_data;
273         } else
274                 return -EBADF;
275
276         xid = GetXid();
277         down(&pCifsFile->fh_sem);
278         if(pCifsFile->invalidHandle == FALSE) {
279                 up(&pCifsFile->fh_sem);
280                 FreeXid(xid);
281                 return 0;
282         }
283
284
285         cifs_sb = CIFS_SB(inode->i_sb);
286         pTcon = cifs_sb->tcon;
287
288         full_path = build_path_from_dentry(file->f_dentry);
289
290         cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
291         if ((file->f_flags & O_ACCMODE) == O_RDONLY)
292                 desiredAccess = GENERIC_READ;
293         else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
294                 desiredAccess = GENERIC_WRITE;
295         else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
296                 /* GENERIC_ALL is too much permission to request */
297                 /* can cause unnecessary access denied on create */
298                 /* desiredAccess = GENERIC_ALL; */
299                 desiredAccess = GENERIC_READ | GENERIC_WRITE;
300         }
301
302         if (oplockEnabled)
303                 oplock = REQ_OPLOCK;
304         else
305                 oplock = FALSE;
306
307                 /* BB pass O_SYNC flag through on file attributes .. BB */
308
309                 /* Also refresh inode by passing in file_info buf returned by SMBOpen
310                    and calling get_inode_info with returned buf (at least
311                    helps non-Unix server case */
312         buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
313         if(buf==0) {
314                 up(&pCifsFile->fh_sem);
315                 if (full_path)
316                         kfree(full_path);
317                 FreeXid(xid);
318                 return -ENOMEM;
319         }
320         rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
321                                 CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls);
322         if (rc) {
323                 up(&pCifsFile->fh_sem);
324                 cFYI(1, ("cifs_open returned 0x%x ", rc));
325                 cFYI(1, ("oplock: %d ", oplock));
326         } else {
327                 pCifsFile->netfid = netfid;
328                 pCifsFile->invalidHandle = FALSE;
329                 up(&pCifsFile->fh_sem);
330                 pCifsInode = CIFS_I(inode);
331                 if(pCifsInode) {
332                         if (pTcon->ses->capabilities & CAP_UNIX)
333                                 rc = cifs_get_inode_info_unix(&inode,
334                                                 full_path, inode->i_sb);
335                         else
336                                 rc = cifs_get_inode_info(&inode,
337                                                 full_path, buf, inode->i_sb);
338
339                         if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
340                                 pCifsInode->clientCanCacheAll =  TRUE;
341                                 pCifsInode->clientCanCacheRead = TRUE;
342                                 cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
343                         } else if((oplock & 0xF) == OPLOCK_READ) {
344                                 pCifsInode->clientCanCacheRead = TRUE;
345                                 pCifsInode->clientCanCacheAll =  FALSE;
346                         } else {
347                                 pCifsInode->clientCanCacheRead = FALSE;
348                                 pCifsInode->clientCanCacheAll =  FALSE;
349                         }
350                         cifs_relock_file(pCifsFile);
351                 }
352         }
353
354         if (buf)
355                 kfree(buf);
356         if (full_path)
357                 kfree(full_path);
358         FreeXid(xid);
359         return rc;
360 }
361
362 int
363 cifs_close(struct inode *inode, struct file *file)
364 {
365         int rc = 0;
366         int xid;
367         struct cifs_sb_info *cifs_sb;
368         struct cifsTconInfo *pTcon;
369         struct cifsFileInfo *pSMBFile =
370                 (struct cifsFileInfo *) file->private_data;
371
372         xid = GetXid();
373
374         cifs_sb = CIFS_SB(inode->i_sb);
375         pTcon = cifs_sb->tcon;
376         if (pSMBFile) {
377                 pSMBFile->closePend    = TRUE;
378                 write_lock(&file->f_owner.lock);
379                 if(pTcon) {
380                         /* no sense reconnecting to close a file that is
381                                 already closed */
382                         if (pTcon->tidStatus != CifsNeedReconnect) {
383                                 write_unlock(&file->f_owner.lock);
384                                 rc = CIFSSMBClose(xid,pTcon,pSMBFile->netfid);
385                                 write_lock(&file->f_owner.lock);
386                         }
387                 }
388                 list_del(&pSMBFile->flist);
389                 list_del(&pSMBFile->tlist);
390                 write_unlock(&file->f_owner.lock);
391                 if(pSMBFile->search_resume_name)
392                         kfree(pSMBFile->search_resume_name);
393                 kfree(file->private_data);
394                 file->private_data = NULL;
395         } else
396                 rc = -EBADF;
397
398         if(list_empty(&(CIFS_I(inode)->openFileList))) {
399                 cFYI(1,("closing last open instance for inode %p",inode));
400                 /* if the file is not open we do not know if we can cache
401                 info on this inode, much less write behind and read ahead */
402                 CIFS_I(inode)->clientCanCacheRead = FALSE;
403                 CIFS_I(inode)->clientCanCacheAll  = FALSE;
404         }
405         if((rc ==0) && CIFS_I(inode)->write_behind_rc)
406                 rc = CIFS_I(inode)->write_behind_rc;
407         FreeXid(xid);
408         return rc;
409 }
410
411 int
412 cifs_closedir(struct inode *inode, struct file *file)
413 {
414         int rc = 0;
415         int xid;
416         struct cifsFileInfo *pSMBFileStruct =
417             (struct cifsFileInfo *) file->private_data;
418
419         cFYI(1, ("Closedir inode = 0x%p with ", inode));
420
421         xid = GetXid();
422
423         if (pSMBFileStruct) {
424                 cFYI(1, ("Freeing private data in close dir"));
425                 kfree(file->private_data);
426                 file->private_data = NULL;
427         }
428         FreeXid(xid);
429         return rc;
430 }
431
432 int
433 cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
434 {
435         int rc, xid;
436         __u32 lockType = LOCKING_ANDX_LARGE_FILES;
437         __u32 numLock = 0;
438         __u32 numUnlock = 0;
439         __u64 length;
440         int wait_flag = FALSE;
441         struct cifs_sb_info *cifs_sb;
442         struct cifsTconInfo *pTcon;
443         length = 1 + pfLock->fl_end - pfLock->fl_start;
444
445         rc = -EACCES;
446
447         xid = GetXid();
448
449         cFYI(1,
450              ("Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld end: %lld",
451               cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
452               pfLock->fl_end));
453
454         if (pfLock->fl_flags & FL_POSIX)
455                 cFYI(1, ("Posix "));
456         if (pfLock->fl_flags & FL_FLOCK)
457                 cFYI(1, ("Flock "));
458         if (pfLock->fl_flags & FL_SLEEP) {
459                 cFYI(1, ("Blocking lock "));
460                 wait_flag = TRUE;
461         }
462         if (pfLock->fl_flags & FL_ACCESS)
463                 cFYI(1, ("Process suspended by mandatory locking - not implemented yet "));
464         if (pfLock->fl_flags & FL_LEASE)
465                 cFYI(1, ("Lease on file - not implemented yet"));
466         if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
467                 cFYI(1, ("Unknown lock flags 0x%x",pfLock->fl_flags));
468
469         if (pfLock->fl_type == F_WRLCK) {
470                 cFYI(1, ("F_WRLCK "));
471                 numLock = 1;
472         } else if (pfLock->fl_type == F_UNLCK) {
473                 cFYI(1, ("F_UNLCK "));
474                 numUnlock = 1;
475         } else if (pfLock->fl_type == F_RDLCK) {
476                 cFYI(1, ("F_RDLCK "));
477                 lockType |= LOCKING_ANDX_SHARED_LOCK;
478                 numLock = 1;
479         } else if (pfLock->fl_type == F_EXLCK) {
480                 cFYI(1, ("F_EXLCK "));
481                 numLock = 1;
482         } else if (pfLock->fl_type == F_SHLCK) {
483                 cFYI(1, ("F_SHLCK "));
484                 lockType |= LOCKING_ANDX_SHARED_LOCK;
485                 numLock = 1;
486         } else
487                 cFYI(1, ("Unknown type of lock "));
488
489         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
490         pTcon = cifs_sb->tcon;
491
492         if (file->private_data == NULL) {
493                 FreeXid(xid);
494                 return -EBADF;
495         }
496
497         if (IS_GETLK(cmd)) {
498                 rc = CIFSSMBLock(xid, pTcon,
499                                  ((struct cifsFileInfo *) file->
500                                   private_data)->netfid,
501                                  length,
502                                  pfLock->fl_start, 0, 1, lockType,
503                                  0 /* wait flag */ );
504                 if (rc == 0) {
505                         rc = CIFSSMBLock(xid, pTcon,
506                                          ((struct cifsFileInfo *) file->
507                                           private_data)->netfid,
508                                          length,
509                                          pfLock->fl_start, 1 /* numUnlock */ ,
510                                          0 /* numLock */ , lockType,
511                                          0 /* wait flag */ );
512                         pfLock->fl_type = F_UNLCK;
513                         if (rc != 0)
514                                 cERROR(1,
515                                         ("Error unlocking previously locked range %d during test of lock ",
516                                         rc));
517                         rc = 0;
518
519                 } else {
520                         /* if rc == ERR_SHARING_VIOLATION ? */
521                         rc = 0; /* do not change lock type to unlock since range in use */
522                 }
523
524                 FreeXid(xid);
525                 return rc;
526         }
527
528         rc = CIFSSMBLock(xid, pTcon,
529                          ((struct cifsFileInfo *) file->private_data)->
530                          netfid, length,
531                          pfLock->fl_start, numUnlock, numLock, lockType,
532                          wait_flag);
533         FreeXid(xid);
534         return rc;
535 }
536
537 ssize_t
538 cifs_write(struct file * file, const char *write_data,
539            size_t write_size, loff_t * poffset)
540 {
541         int rc = 0;
542         unsigned int bytes_written = 0;
543         unsigned int total_written;
544         struct cifs_sb_info *cifs_sb;
545         struct cifsTconInfo *pTcon;
546         int xid, long_op;
547         struct cifsFileInfo * open_file;
548
549         xid = GetXid();
550
551         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
552         pTcon = cifs_sb->tcon;
553
554         /*cFYI(1,
555            (" write %d bytes to offset %lld of %s", write_size,
556            *poffset, file->f_dentry->d_name.name)); */
557
558         if (file->private_data == NULL) {
559                 FreeXid(xid);
560                 return -EBADF;
561         }
562         open_file = (struct cifsFileInfo *) file->private_data;
563
564         if(file->f_dentry->d_inode == NULL) {
565                 FreeXid(xid);
566                 return -EBADF;
567         }
568
569         if (*poffset > file->f_dentry->d_inode->i_size)
570                 long_op = 2;  /* writes past end of file can take a long time */
571         else
572                 long_op = 1;
573
574         for (total_written = 0; write_size > total_written;
575              total_written += bytes_written) {
576                 rc = -EAGAIN;
577                 while(rc == -EAGAIN) {
578                         if(file->private_data == NULL) {
579                                 /* file has been closed on us */
580                                 FreeXid(xid);
581                                 return total_written;
582                         }
583                         if ((open_file->invalidHandle) && (!open_file->closePend)) {
584                                 if((file->f_dentry == NULL) || (file->f_dentry->d_inode == NULL)) {
585                                         FreeXid(xid);
586                                         return total_written;
587                                 }
588                                 rc = cifs_reopen_file(file->f_dentry->d_inode,file);
589                                 if(rc != 0)
590                                         break;
591                         }
592
593                         rc = CIFSSMBWrite(xid, pTcon,
594                                    open_file->netfid,
595                                   write_size - total_written, *poffset,
596                                   &bytes_written,
597                                   write_data + total_written, long_op);
598                 }
599                 if (rc || (bytes_written == 0)) {
600                         if (total_written)
601                                 break;
602                         else {
603                                 FreeXid(xid);
604                                 return rc;
605                         }
606                 } else
607                         *poffset += bytes_written;
608                 long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
609         }
610
611         /* since the write may have blocked check these pointers again */
612         if(file->f_dentry) {
613                 if(file->f_dentry->d_inode) {
614                         file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime =
615                                 CURRENT_TIME;
616                         if (bytes_written > 0) {
617                                 if (*poffset > file->f_dentry->d_inode->i_size)
618                                         i_size_write(file->f_dentry->d_inode, *poffset);
619                         }
620                         mark_inode_dirty_sync(file->f_dentry->d_inode);
621                 }
622         }
623         FreeXid(xid);
624         return total_written;
625 }
626
627 static int
628 cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
629 {
630         struct address_space *mapping = page->mapping;
631         loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
632         char * write_data;
633         int rc = -EFAULT;
634         int bytes_written = 0;
635         struct cifs_sb_info *cifs_sb;
636         struct cifsTconInfo *pTcon;
637         struct inode *inode = page->mapping->host;
638         struct cifsInodeInfo *cifsInode;
639         struct cifsFileInfo *open_file = NULL;
640         struct list_head *tmp;
641         struct list_head *tmp1;
642
643         cifs_sb = CIFS_SB(inode->i_sb);
644         pTcon = cifs_sb->tcon;
645
646         /* figure out which file struct to use 
647         if (file->private_data == NULL) {
648                 return -EBADF;
649         }     
650          */
651         if (!mapping) {
652                 return -EFAULT;
653         } else if(!mapping->host) {
654                 return -EFAULT;
655         }
656
657         offset += (loff_t)from;
658         write_data = kmap(page);
659         write_data += from;
660
661         if((to > PAGE_CACHE_SIZE) || (from > to)) {
662                 kunmap(page);
663                 return -EIO;
664         }
665
666         /* racing with truncate? */
667         if(offset > mapping->host->i_size) {
668                 kunmap(page);
669                 return 0; /* don't care */
670         }
671
672         /* check to make sure that we are not extending the file */
673         if(mapping->host->i_size - offset < (loff_t)to)
674                 to = (unsigned)(mapping->host->i_size - offset); 
675                 
676
677         cifsInode = CIFS_I(mapping->host);
678         read_lock(&GlobalSMBSeslock); 
679         list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
680                 open_file = list_entry(tmp,struct cifsFileInfo, flist);
681                 /* We check if file is open for writing first */
682                 if((open_file->pfile) && 
683                    ((open_file->pfile->f_flags & O_RDWR) || 
684                         (open_file->pfile->f_flags & O_WRONLY))) {
685                         read_unlock(&GlobalSMBSeslock);
686                         bytes_written = cifs_write(open_file->pfile, write_data,
687                                         to-from, &offset);
688                         read_lock(&GlobalSMBSeslock);
689                 /* Does mm or vfs already set times? */
690                         inode->i_atime = inode->i_mtime = CURRENT_TIME;
691                         if ((bytes_written > 0) && (offset)) {
692                                 rc = 0;
693                         } else if(bytes_written < 0) {
694                                 rc = bytes_written;
695                         }
696                         break;  /* now that we found a valid file handle
697                                 and tried to write to it we are done, no
698                                 sense continuing to loop looking for another */
699                 }
700                 if(tmp->next == NULL) {
701                         cFYI(1,("File instance %p removed",tmp));
702                         break;
703                 }
704         }
705         read_unlock(&GlobalSMBSeslock);
706         if(open_file == NULL) {
707                 cFYI(1,("No writeable filehandles for inode"));
708                 rc = -EIO;
709         }
710
711         kunmap(page);
712         return rc;
713 }
714
715 #if 0
716 static int
717 cifs_writepages(struct address_space *mapping, struct writeback_control *wbc)
718 {
719         int rc = -EFAULT;
720         int xid;
721
722         xid = GetXid();
723 /* call 16K write then Setpageuptodate */
724         FreeXid(xid);
725         return rc;
726 }
727 #endif
728
729 static int
730 cifs_writepage(struct page* page, struct writeback_control *wbc)
731 {
732         int rc = -EFAULT;
733         int xid;
734
735         xid = GetXid();
736 /* BB add check for wbc flags */
737         page_cache_get(page);
738         
739         rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE);
740         SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
741         unlock_page(page);
742         page_cache_release(page);       
743         FreeXid(xid);
744         return rc;
745 }
746
747 static int
748 cifs_commit_write(struct file *file, struct page *page, unsigned offset,
749                   unsigned to)
750 {
751         int xid;
752         int rc = 0;
753         struct inode *inode = page->mapping->host;
754         loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
755         /* struct cifsFileInfo *open_file;
756         struct cifs_sb_info *cifs_sb; */
757
758         xid = GetXid();
759         cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to));
760         if (position > inode->i_size){
761                 i_size_write(inode, position);
762                 /*if (file->private_data == NULL) {
763                         rc = -EBADF;
764                 } else {
765                         open_file = (struct cifsFileInfo *)file->private_data;
766                         cifs_sb = CIFS_SB(inode->i_sb);
767                         rc = -EAGAIN;
768                         while(rc == -EAGAIN) {
769                                 if((open_file->invalidHandle) && 
770                                   (!open_file->closePend)) {
771                                         rc = cifs_reopen_file(file->f_dentry->d_inode,file);
772                                         if(rc != 0)
773                                                 break;
774                                 }
775                                 if(!open_file->closePend) {
776                                         rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, 
777                                                 position, open_file->netfid,
778                                                 open_file->pid,FALSE);
779                                 } else {
780                                         rc = -EBADF;
781                                         break;
782                                 }
783                         }
784                         cFYI(1,(" SetEOF (commit write) rc = %d",rc));
785                 }*/
786         }
787         set_page_dirty(page);
788
789         FreeXid(xid);
790         return rc;
791 }
792
793 int
794 cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
795 {
796         int xid;
797         int rc = 0;
798         struct inode * inode = file->f_dentry->d_inode;
799
800         xid = GetXid();
801
802         cFYI(1, ("Sync file - name: %s datasync: 0x%x ", 
803                 dentry->d_name.name, datasync));
804         
805         rc = filemap_fdatawrite(inode->i_mapping);
806         if(rc == 0)
807                 CIFS_I(inode)->write_behind_rc = 0;
808         FreeXid(xid);
809         return rc;
810 }
811
812 /* static int
813 cifs_sync_page(struct page *page)
814 {
815         struct address_space *mapping;
816         struct inode *inode;
817         unsigned long index = page->index;
818         unsigned int rpages = 0;
819         int rc = 0;
820
821         cFYI(1,("sync page %p",page));
822         mapping = page->mapping;
823         if (!mapping)
824                 return 0;
825         inode = mapping->host;
826         if (!inode)
827                 return 0;*/
828
829 /*      fill in rpages then 
830     result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */
831
832 /*   cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
833
834         if (rc < 0)
835                 return rc;
836         return 0;
837 } */
838
839 /*
840  * As file closes, flush all cached write data for this inode checking
841  * for write behind errors.
842  *
843  */
844 int cifs_flush(struct file *file)
845 {
846         struct inode * inode = file->f_dentry->d_inode;
847         int rc = 0;
848
849         /* Rather than do the steps manually: */
850         /* lock the inode for writing */
851         /* loop through pages looking for write behind data (dirty pages) */
852         /* coalesce into contiguous 16K (or smaller) chunks to write to server */
853         /* send to server (prefer in parallel) */
854         /* deal with writebehind errors */
855         /* unlock inode for writing */
856         /* filemapfdatawrite appears easier for the time being */
857
858         rc = filemap_fdatawrite(inode->i_mapping);
859         if(rc == 0) /* reset wb rc if we were able to write out dirty pages */
860                 CIFS_I(inode)->write_behind_rc = 0;
861                 
862         cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc));
863
864         return rc;
865 }
866
867
868 ssize_t
869 cifs_read(struct file * file, char *read_data, size_t read_size,
870           loff_t * poffset)
871 {
872         int rc = -EACCES;
873         unsigned int bytes_read = 0;
874         unsigned int total_read;
875         unsigned int current_read_size;
876         struct cifs_sb_info *cifs_sb;
877         struct cifsTconInfo *pTcon;
878         int xid;
879         char * current_offset;
880         struct cifsFileInfo * open_file;
881
882         xid = GetXid();
883         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
884         pTcon = cifs_sb->tcon;
885
886         if (file->private_data == NULL) {
887                 FreeXid(xid);
888                 return -EBADF;
889         }
890         open_file = (struct cifsFileInfo *)file->private_data;
891
892         for (total_read = 0,current_offset=read_data; read_size > total_read;
893                                 total_read += bytes_read,current_offset+=bytes_read) {
894                 current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
895                 rc = -EAGAIN;
896                 while(rc == -EAGAIN) {
897                         if ((open_file->invalidHandle) && (!open_file->closePend)) {
898                                 rc = cifs_reopen_file(file->f_dentry->d_inode,file);
899                                 if(rc != 0)
900                                         break;
901                         }
902
903                         rc = CIFSSMBRead(xid, pTcon,
904                                  open_file->netfid,
905                                  current_read_size, *poffset,
906                                  &bytes_read, &current_offset);
907                 }
908                 if (rc || (bytes_read == 0)) {
909                         if (total_read) {
910                                 break;
911                         } else {
912                                 FreeXid(xid);
913                                 return rc;
914                         }
915                 } else {
916                         *poffset += bytes_read;
917                 }
918         }
919
920         FreeXid(xid);
921         return total_read;
922 }
923
924 int cifs_file_mmap(struct file * file, struct vm_area_struct * vma)
925 {
926         struct dentry * dentry = file->f_dentry;
927         int     rc, xid;
928
929         xid = GetXid();
930         rc = cifs_revalidate(dentry);
931         if (rc) {
932                 cFYI(1,("Validation prior to mmap failed, error=%d", rc));
933                 FreeXid(xid);
934                 return rc;
935         }
936         rc = generic_file_mmap(file, vma);
937         FreeXid(xid);
938         return rc;
939 }
940
941 static void cifs_copy_cache_pages(struct address_space *mapping, 
942                 struct list_head *pages, int bytes_read, 
943                 char *data,struct pagevec * plru_pvec)
944 {
945         struct page *page;
946         char * target;
947
948         while (bytes_read > 0) {
949                 if(list_empty(pages))
950                         break;
951
952                 page = list_entry(pages->prev, struct page, lru);
953                 list_del(&page->lru);
954
955                 if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
956                         page_cache_release(page);
957                         cFYI(1,("Add page cache failed"));
958                         continue;
959                 }
960
961                 target = kmap_atomic(page,KM_USER0);
962
963                 if(PAGE_CACHE_SIZE > bytes_read) {
964                         memcpy(target,data,bytes_read);
965                         /* zero the tail end of this partial page */
966                         memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read);
967                         bytes_read = 0;
968                 } else {
969                         memcpy(target,data,PAGE_CACHE_SIZE);
970                         bytes_read -= PAGE_CACHE_SIZE;
971                 }
972                 kunmap_atomic(target,KM_USER0);
973
974                 flush_dcache_page(page);
975                 SetPageUptodate(page);
976                 unlock_page(page);
977                 if (!pagevec_add(plru_pvec, page))
978                         __pagevec_lru_add(plru_pvec);
979                 data += PAGE_CACHE_SIZE;
980         }
981         return;
982 }
983
984
985 static int
986 cifs_readpages(struct file *file, struct address_space *mapping,
987                 struct list_head *page_list, unsigned num_pages)
988 {
989         int rc = -EACCES;
990         int xid;
991         loff_t offset;
992         struct page * page;
993         struct cifs_sb_info *cifs_sb;
994         struct cifsTconInfo *pTcon;
995         int bytes_read = 0;
996         unsigned int read_size,i;
997         char * smb_read_data = 0;
998         struct smb_com_read_rsp * pSMBr;
999         struct pagevec lru_pvec;
1000         struct cifsFileInfo * open_file;
1001
1002         xid = GetXid();
1003         if (file->private_data == NULL) {
1004                 FreeXid(xid);
1005                 return -EBADF;
1006         }
1007         open_file = (struct cifsFileInfo *)file->private_data;
1008         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1009         pTcon = cifs_sb->tcon;
1010
1011         pagevec_init(&lru_pvec, 0);
1012
1013         for(i = 0;i<num_pages;) {
1014                 unsigned contig_pages;
1015                 struct page * tmp_page;
1016                 unsigned long expected_index;
1017
1018                 if(list_empty(page_list)) {
1019                         break;
1020                 }
1021                 page = list_entry(page_list->prev, struct page, lru);
1022                 offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1023
1024                 /* count adjacent pages that we will read into */
1025                 contig_pages = 0;
1026                 expected_index = list_entry(page_list->prev,struct page,lru)->index;
1027                 list_for_each_entry_reverse(tmp_page,page_list,lru) {
1028                         if(tmp_page->index == expected_index) {
1029                                 contig_pages++;
1030                                 expected_index++;
1031                         } else {
1032                                 break; 
1033                         }
1034                 }
1035                 if(contig_pages + i >  num_pages) {
1036                         contig_pages = num_pages - i;
1037                 }
1038
1039                 /* for reads over a certain size could initiate async read ahead */
1040
1041                 read_size = contig_pages * PAGE_CACHE_SIZE;
1042                 /* Read size needs to be in multiples of one page */
1043                 read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK);
1044
1045                 rc = -EAGAIN;
1046                 while(rc == -EAGAIN) {
1047                         if ((open_file->invalidHandle) && (!open_file->closePend)) {
1048                                 rc = cifs_reopen_file(file->f_dentry->d_inode,file);
1049                                 if(rc != 0)
1050                                         break;
1051                         }
1052
1053                         rc = CIFSSMBRead(xid, pTcon,
1054                                 open_file->netfid,
1055                                 read_size, offset,
1056                                 &bytes_read, &smb_read_data);
1057                         /* BB need to check return code here */
1058                         if(rc== -EAGAIN) {
1059                                 if(smb_read_data) {
1060                                         cifs_buf_release(smb_read_data);
1061                                         smb_read_data = 0;
1062                                 }
1063                         }
1064                 }
1065                 if ((rc < 0) || (smb_read_data == NULL)) {
1066                         cFYI(1,("Read error in readpages: %d",rc));
1067                         /* clean up remaing pages off list */
1068                         while (!list_empty(page_list) && (i < num_pages)) {
1069                                 page = list_entry(page_list->prev, struct page, lru);
1070                                 list_del(&page->lru);
1071                                 page_cache_release(page);
1072                         }
1073                         break;
1074                 } else if (bytes_read > 0) {
1075                         pSMBr = (struct smb_com_read_rsp *)smb_read_data;
1076                         cifs_copy_cache_pages(mapping, page_list, bytes_read,
1077                                 smb_read_data + 4 /* RFC1001 hdr */ +
1078                                 le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
1079
1080                         i +=  bytes_read >> PAGE_CACHE_SHIFT;
1081
1082                         if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
1083                                 cFYI(1,("Partial page %d of %d read to cache",i++,num_pages));
1084
1085                                 i++; /* account for partial page */
1086
1087                                 /* server copy of file can have smaller size than client */
1088                                 /* BB do we need to verify this common case ? this case is ok - 
1089                                 if we are at server EOF we will hit it on next read */
1090
1091                         /* while(!list_empty(page_list) && (i < num_pages)) {
1092                                         page = list_entry(page_list->prev,struct page, list);
1093                                         list_del(&page->list);
1094                                         page_cache_release(page);
1095                                 }
1096                                 break; */
1097                         }
1098                 } else {
1099                         cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset)); 
1100                         /* BB turn off caching and do new lookup on file size at server? */
1101                         while (!list_empty(page_list) && (i < num_pages)) {
1102                                 page = list_entry(page_list->prev, struct page, lru);
1103                                 list_del(&page->lru);
1104                                 page_cache_release(page); /* BB removeme - replace with zero of page? */
1105                         }
1106                         break;
1107                 }
1108                 if(smb_read_data) {
1109                         cifs_buf_release(smb_read_data);
1110                         smb_read_data = 0;
1111                 }
1112                 bytes_read = 0;
1113         }
1114
1115         pagevec_lru_add(&lru_pvec);
1116
1117 /* need to free smb_read_data buf before exit */
1118         if(smb_read_data) {
1119                 cifs_buf_release(smb_read_data);
1120                 smb_read_data = 0;
1121         } 
1122
1123         FreeXid(xid);
1124         return rc;
1125 }
1126
1127 static int
1128 cifs_readpage(struct file *file, struct page *page)
1129 {
1130         loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
1131         char * read_data;
1132         int rc = -EACCES;
1133         int xid;
1134
1135         xid = GetXid();
1136
1137         if (file->private_data == NULL) {
1138                 FreeXid(xid);
1139                 return -EBADF;
1140         }
1141
1142         cFYI(0,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset));
1143
1144         page_cache_get(page);
1145         read_data = kmap(page);
1146         /* for reads over a certain size could initiate async read ahead */
1147
1148         rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, &offset);
1149
1150         if (rc < 0)
1151                 goto io_error;
1152         else {
1153                 cFYI(1,("Bytes read %d ",rc));
1154         }
1155
1156         file->f_dentry->d_inode->i_atime = CURRENT_TIME;
1157
1158         if(PAGE_CACHE_SIZE > rc) {
1159                 memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc);
1160         }
1161         flush_dcache_page(page);
1162         SetPageUptodate(page);
1163         rc = 0;
1164
1165 io_error:
1166         kunmap(page);
1167         unlock_page(page);
1168
1169         page_cache_release(page);
1170         FreeXid(xid);
1171         return rc;
1172 }
1173
1174 void
1175 fill_in_inode(struct inode *tmp_inode,
1176               FILE_DIRECTORY_INFO * pfindData, int *pobject_type)
1177 {
1178         struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
1179         struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
1180
1181         pfindData->ExtFileAttributes =
1182             le32_to_cpu(pfindData->ExtFileAttributes);
1183         pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
1184         pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
1185         cifsInfo->cifsAttrs = pfindData->ExtFileAttributes;
1186         cifsInfo->time = jiffies;
1187
1188         /* Linux can not store file creation time unfortunately so ignore it */
1189         tmp_inode->i_atime =
1190             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
1191         tmp_inode->i_mtime =
1192             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
1193         tmp_inode->i_ctime =
1194             cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
1195         /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
1196         /* 2767 perms - indicate mandatory locking */
1197                 /* BB fill in uid and gid here? with help from winbind? 
1198                         or retrieve from NTFS stream extended attribute */
1199         if(atomic_read(&cifsInfo->inUse) == 0) {
1200                 tmp_inode->i_uid = cifs_sb->mnt_uid;
1201                 tmp_inode->i_gid = cifs_sb->mnt_gid;
1202                 /* set default mode. will override for dirs below */
1203                 tmp_inode->i_mode = cifs_sb->mnt_file_mode;
1204         }
1205
1206         cFYI(0,
1207              ("CIFS FFIRST: Attributes came in as 0x%x",
1208               pfindData->ExtFileAttributes));
1209         if (pfindData->ExtFileAttributes & ATTR_REPARSE) {
1210                 *pobject_type = DT_LNK;
1211                 /* BB can this and S_IFREG or S_IFDIR be set as in Windows? */
1212                 tmp_inode->i_mode |= S_IFLNK;
1213         } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) {
1214                 *pobject_type = DT_DIR;
1215                 /* override default perms since we do not lock dirs */
1216                 if(atomic_read(&cifsInfo->inUse) == 0) {
1217                         tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
1218                 }
1219                 tmp_inode->i_mode |= S_IFDIR;
1220         } else {
1221                 *pobject_type = DT_REG;
1222                 tmp_inode->i_mode |= S_IFREG;
1223                 if(pfindData->ExtFileAttributes & ATTR_READONLY)
1224                         tmp_inode->i_mode &= ~(S_IWUGO);
1225
1226         }/* could add code here - to validate if device or weird share type? */
1227
1228         /* can not fill in nlink here as in qpathinfo version and Unx search */
1229         if(atomic_read(&cifsInfo->inUse) == 0) {
1230                 atomic_set(&cifsInfo->inUse,1);
1231         }
1232
1233         i_size_write(tmp_inode,pfindData->EndOfFile);
1234         tmp_inode->i_blocks =
1235                 (tmp_inode->i_blksize - 1 + pfindData->AllocationSize) >> tmp_inode->i_blkbits;
1236         if (pfindData->AllocationSize < pfindData->EndOfFile)
1237                 cFYI(1, ("Possible sparse file: allocation size less than end of file "));
1238         cFYI(1,
1239              ("File Size %ld and blocks %ld and blocksize %ld",
1240               (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks,
1241               tmp_inode->i_blksize));
1242         if (S_ISREG(tmp_inode->i_mode)) {
1243                 cFYI(1, (" File inode "));
1244                 tmp_inode->i_op = &cifs_file_inode_ops;
1245                 tmp_inode->i_fop = &cifs_file_ops;
1246                 tmp_inode->i_data.a_ops = &cifs_addr_ops;
1247         } else if (S_ISDIR(tmp_inode->i_mode)) {
1248                 cFYI(1, (" Directory inode"));
1249                 tmp_inode->i_op = &cifs_dir_inode_ops;
1250                 tmp_inode->i_fop = &cifs_dir_ops;
1251         } else if (S_ISLNK(tmp_inode->i_mode)) {
1252                 cFYI(1, (" Symbolic Link inode "));
1253                 tmp_inode->i_op = &cifs_symlink_inode_ops;
1254         } else {
1255                 cFYI(1, (" Init special inode "));
1256                 init_special_inode(tmp_inode, tmp_inode->i_mode,
1257                                    tmp_inode->i_rdev);
1258         }
1259 }
1260
1261 void
1262 unix_fill_in_inode(struct inode *tmp_inode,
1263                    FILE_UNIX_INFO * pfindData, int *pobject_type)
1264 {
1265         struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
1266         cifsInfo->time = jiffies;
1267         atomic_inc(&cifsInfo->inUse);
1268
1269         tmp_inode->i_atime =
1270             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
1271         tmp_inode->i_mtime =
1272             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
1273         tmp_inode->i_ctime =
1274             cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));
1275
1276         tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
1277         pfindData->Type = le32_to_cpu(pfindData->Type);
1278         if (pfindData->Type == UNIX_FILE) {
1279                 *pobject_type = DT_REG;
1280                 tmp_inode->i_mode |= S_IFREG;
1281         } else if (pfindData->Type == UNIX_SYMLINK) {
1282                 *pobject_type = DT_LNK;
1283                 tmp_inode->i_mode |= S_IFLNK;
1284         } else if (pfindData->Type == UNIX_DIR) {
1285                 *pobject_type = DT_DIR;
1286                 tmp_inode->i_mode |= S_IFDIR;
1287         } else if (pfindData->Type == UNIX_CHARDEV) {
1288                 *pobject_type = DT_CHR;
1289                 tmp_inode->i_mode |= S_IFCHR;
1290         } else if (pfindData->Type == UNIX_BLOCKDEV) {
1291                 *pobject_type = DT_BLK;
1292                 tmp_inode->i_mode |= S_IFBLK;
1293         } else if (pfindData->Type == UNIX_FIFO) {
1294                 *pobject_type = DT_FIFO;
1295                 tmp_inode->i_mode |= S_IFIFO;
1296         } else if (pfindData->Type == UNIX_SOCKET) {
1297                 *pobject_type = DT_SOCK;
1298                 tmp_inode->i_mode |= S_IFSOCK;
1299         }
1300
1301         tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
1302         tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
1303         tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
1304
1305         pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes);
1306         pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
1307         i_size_write(tmp_inode,pfindData->EndOfFile);
1308         tmp_inode->i_blocks =
1309                 (tmp_inode->i_blksize - 1 + pfindData->NumOfBytes) >> tmp_inode->i_blkbits;
1310
1311         if (S_ISREG(tmp_inode->i_mode)) {
1312                 cFYI(1, ("File inode"));
1313                 tmp_inode->i_op = &cifs_file_inode_ops;
1314                 tmp_inode->i_fop = &cifs_file_ops;
1315                 tmp_inode->i_data.a_ops = &cifs_addr_ops;
1316         } else if (S_ISDIR(tmp_inode->i_mode)) {
1317                 cFYI(1, ("Directory inode"));
1318                 tmp_inode->i_op = &cifs_dir_inode_ops;
1319                 tmp_inode->i_fop = &cifs_dir_ops;
1320         } else if (S_ISLNK(tmp_inode->i_mode)) {
1321                 cFYI(1, ("Symbolic Link inode"));
1322                 tmp_inode->i_op = &cifs_symlink_inode_ops;
1323 /* tmp_inode->i_fop = *//* do not need to set to anything */
1324         } else {
1325                 cFYI(1, ("Special inode")); 
1326                 init_special_inode(tmp_inode, tmp_inode->i_mode,
1327                                    tmp_inode->i_rdev);
1328         }
1329 }
1330
1331 static void
1332 construct_dentry(struct qstr *qstring, struct file *file,
1333                  struct inode **ptmp_inode, struct dentry **pnew_dentry)
1334 {
1335         struct dentry *tmp_dentry;
1336         struct cifs_sb_info *cifs_sb;
1337         struct cifsTconInfo *pTcon;
1338
1339         cFYI(1, ("For %s ", qstring->name));
1340         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1341         pTcon = cifs_sb->tcon;
1342
1343         qstring->hash = full_name_hash(qstring->name, qstring->len);
1344         tmp_dentry = d_lookup(file->f_dentry, qstring);
1345         if (tmp_dentry) {
1346                 cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode));
1347                 *ptmp_inode = tmp_dentry->d_inode;
1348                 /* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */
1349                 if(*ptmp_inode == NULL) {
1350                         *ptmp_inode = new_inode(file->f_dentry->d_sb);
1351                         d_instantiate(tmp_dentry, *ptmp_inode);
1352                 }
1353         } else {
1354                 tmp_dentry = d_alloc(file->f_dentry, qstring);
1355                 if(tmp_dentry == NULL) {
1356                         cERROR(1,("Failed allocating dentry"));
1357                         return;
1358                 }
1359                         
1360                 *ptmp_inode = new_inode(file->f_dentry->d_sb);
1361                 tmp_dentry->d_op = &cifs_dentry_ops;
1362                 cFYI(0, (" instantiate dentry 0x%p with inode 0x%p ",
1363                          tmp_dentry, *ptmp_inode));
1364                 d_instantiate(tmp_dentry, *ptmp_inode);
1365                 d_rehash(tmp_dentry);
1366         }
1367
1368         tmp_dentry->d_time = jiffies;
1369         *pnew_dentry = tmp_dentry;
1370 }
1371
1372 static void reset_resume_key(struct file * dir_file, 
1373                                 unsigned char * filename, 
1374                                 unsigned int len,int Unicode,struct nls_table * nls_tab) {
1375         struct cifsFileInfo *cifsFile;
1376
1377         cifsFile = (struct cifsFileInfo *)dir_file->private_data;
1378         if(cifsFile == NULL)
1379                 return;
1380         if(cifsFile->search_resume_name) {
1381                 kfree(cifsFile->search_resume_name);
1382         }
1383
1384         if(Unicode) 
1385                 len *= 2;
1386         cifsFile->resume_name_length = len;
1387
1388         cifsFile->search_resume_name = 
1389                 kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
1390
1391         if(cifsFile->search_resume_name == NULL) {
1392                 cERROR(1,("failed new resume key allocate, length %d",
1393                                   cifsFile->resume_name_length));
1394                 return;
1395         }
1396         if(Unicode)
1397                 cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name,
1398                         filename, len, nls_tab);
1399         else
1400                 memcpy(cifsFile->search_resume_name, filename, 
1401                    cifsFile->resume_name_length);
1402         cFYI(1,("Reset resume key to: %s with len %d",filename,len));
1403         return;
1404 }
1405
1406
1407
1408 static int
1409 cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData,
1410              struct file *file, filldir_t filldir, void *direntry)
1411 {
1412         struct inode *tmp_inode;
1413         struct dentry *tmp_dentry;
1414         int object_type,rc;
1415
1416         pqstring->name = pfindData->FileName;
1417         pqstring->len = pfindData->FileNameLength;
1418
1419         construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
1420
1421         fill_in_inode(tmp_inode, pfindData, &object_type);
1422         rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos,
1423                 tmp_inode->i_ino, object_type);
1424         if(rc) {
1425                 /* due to readdir error we need to recalculate resume 
1426                 key so next readdir will restart on right entry */
1427                 cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName));
1428         }
1429         dput(tmp_dentry);
1430         return rc;
1431 }
1432
1433 static int
1434 cifs_filldir_unix(struct qstr *pqstring,
1435                   FILE_UNIX_INFO * pUnixFindData, struct file *file,
1436                   filldir_t filldir, void *direntry)
1437 {
1438         struct inode *tmp_inode;
1439         struct dentry *tmp_dentry;
1440         int object_type, rc;
1441
1442         pqstring->name = pUnixFindData->FileName;
1443         pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF);
1444
1445         construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
1446
1447         unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type);
1448         rc = filldir(direntry, pUnixFindData->FileName, pqstring->len,
1449                 file->f_pos, tmp_inode->i_ino, object_type);
1450         if(rc) {
1451                 /* due to readdir error we need to recalculate resume 
1452                         key so next readdir will restart on right entry */
1453                 cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName));
1454         }
1455         dput(tmp_dentry);
1456         return rc;
1457 }
1458
1459 int
1460 cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
1461 {
1462         int rc = 0;
1463         int xid;
1464         int Unicode = FALSE;
1465         int UnixSearch = FALSE;
1466         unsigned int bufsize, i;
1467         __u16 searchHandle;
1468         struct cifs_sb_info *cifs_sb;
1469         struct cifsTconInfo *pTcon;
1470         struct cifsFileInfo *cifsFile = NULL;
1471         char *full_path = NULL;
1472         char *data;
1473         struct qstr qstring;
1474         T2_FFIRST_RSP_PARMS findParms;
1475         T2_FNEXT_RSP_PARMS findNextParms;
1476         FILE_DIRECTORY_INFO *pfindData;
1477         FILE_DIRECTORY_INFO *lastFindData;
1478         FILE_UNIX_INFO *pfindDataUnix;
1479
1480         xid = GetXid();
1481
1482         cifs_sb = CIFS_SB(file->f_dentry->d_sb);
1483         pTcon = cifs_sb->tcon;
1484         bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE;
1485         if(bufsize > CIFS_MAX_MSGSIZE) {
1486                 FreeXid(xid);
1487                 return -EIO;
1488         }
1489         data = kmalloc(bufsize, GFP_KERNEL);
1490         pfindData = (FILE_DIRECTORY_INFO *) data;
1491
1492         full_path = build_wildcard_path_from_dentry(file->f_dentry);
1493
1494         cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
1495
1496         switch ((int) file->f_pos) {
1497         case 0:
1498                 if (filldir(direntry, ".", 1, file->f_pos,
1499                      file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
1500                         cERROR(1, ("Filldir for current dir failed "));
1501                         break;
1502                 }
1503                 file->f_pos++;
1504                 /* fallthrough */
1505         case 1:
1506                 if (filldir(direntry, "..", 2, file->f_pos,
1507                      file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
1508                         cERROR(1, ("Filldir for parent dir failed "));
1509                         break;
1510                 }
1511                 file->f_pos++;
1512                 /* fallthrough */
1513         case 2:
1514                 if (file->private_data != NULL) {
1515                         cifsFile =
1516                                 (struct cifsFileInfo *) file->private_data;
1517                         if (cifsFile->endOfSearch) {
1518                                 if(cifsFile->emptyDir) {
1519                                         cFYI(1, ("End of search, empty dir"));
1520                                         rc = 0;
1521                                         break;
1522                                 }
1523                         } else {
1524                                 cifsFile->invalidHandle = TRUE;
1525                                 CIFSFindClose(xid, pTcon, cifsFile->netfid);
1526                         }
1527                         if(cifsFile->search_resume_name) {
1528                                 kfree(cifsFile->search_resume_name);
1529                                 cifsFile->search_resume_name = NULL;
1530                         }
1531                 }
1532                 rc = CIFSFindFirst(xid, pTcon, full_path, pfindData,
1533                                 &findParms, cifs_sb->local_nls,
1534                                 &Unicode, &UnixSearch);
1535                 cFYI(1, ("Count: %d  End: %d ", findParms.SearchCount,
1536                         findParms.EndofSearch));
1537  
1538                 if (rc == 0) {
1539                         searchHandle = findParms.SearchHandle;
1540                         if(file->private_data == NULL)
1541                                 file->private_data =
1542                                         kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
1543                         if (file->private_data) {
1544                                 memset(file->private_data, 0,
1545                                        sizeof (struct cifsFileInfo));
1546                                 cifsFile =
1547                                     (struct cifsFileInfo *) file->private_data;
1548                                 cifsFile->netfid = searchHandle;
1549                                 cifsFile->invalidHandle = FALSE;
1550                                 init_MUTEX(&cifsFile->fh_sem);
1551                         } else {
1552                                 rc = -ENOMEM;
1553                                 break;
1554                         }
1555
1556                         renew_parental_timestamps(file->f_dentry);
1557                         lastFindData = 
1558                                 (FILE_DIRECTORY_INFO *) ((char *) pfindData + 
1559                                         findParms.LastNameOffset);
1560                         if((char *)lastFindData > (char *)pfindData + bufsize) {
1561                                 cFYI(1,("last search entry past end of packet"));
1562                                 rc = -EIO;
1563                                 break;
1564                         }
1565                         /* Offset of resume key same for levels 257 and 514 */
1566                         cifsFile->resume_key = lastFindData->FileIndex;
1567                         if(UnixSearch == FALSE) {
1568                                 cifsFile->resume_name_length = 
1569                                         le32_to_cpu(lastFindData->FileNameLength);
1570                                 if(cifsFile->resume_name_length > bufsize - 64) {
1571                                         cFYI(1,("Illegal resume file name length %d",
1572                                                 cifsFile->resume_name_length));
1573                                         rc = -ENOMEM;
1574                                         break;
1575                                 }
1576                                 cifsFile->search_resume_name = 
1577                                         kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
1578                                 cFYI(1,("Last file: %s with name %d bytes long",
1579                                         lastFindData->FileName,
1580                                         cifsFile->resume_name_length));
1581                                 memcpy(cifsFile->search_resume_name,
1582                                         lastFindData->FileName, 
1583                                         cifsFile->resume_name_length);
1584                         } else {
1585                                 pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
1586                                 if (Unicode == TRUE) {
1587                                         for(i=0;(pfindDataUnix->FileName[i] 
1588                                                     | pfindDataUnix->FileName[i+1]);
1589                                                 i+=2) {
1590                                                 if(i > bufsize-64)
1591                                                         break;
1592                                         }
1593                                         cifsFile->resume_name_length = i + 2;
1594                                 } else {
1595                                         cifsFile->resume_name_length = 
1596                                                 strnlen(pfindDataUnix->FileName,
1597                                                         bufsize-63);
1598                                 }
1599                                 if(cifsFile->resume_name_length > bufsize - 64) {
1600                                         cFYI(1,("Illegal resume file name length %d",
1601                                                 cifsFile->resume_name_length));
1602                                         rc = -ENOMEM;
1603                                         break;
1604                                 }
1605                                 cifsFile->search_resume_name = 
1606                                         kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
1607                                 cFYI(1,("Last file: %s with name %d bytes long",
1608                                         pfindDataUnix->FileName,
1609                                         cifsFile->resume_name_length));
1610                                 memcpy(cifsFile->search_resume_name,
1611                                         pfindDataUnix->FileName, 
1612                                         cifsFile->resume_name_length);
1613                         }
1614                         for (i = 2; i < (unsigned int)findParms.SearchCount + 2; i++) {
1615                                 if (UnixSearch == FALSE) {
1616                                         pfindData->FileNameLength =
1617                                           le32_to_cpu(pfindData->FileNameLength);
1618                                         if (Unicode == TRUE)
1619                                                 pfindData->FileNameLength =
1620                                                     cifs_strfromUCS_le
1621                                                     (pfindData->FileName,
1622                                                      (wchar_t *)
1623                                                      pfindData->FileName,
1624                                                      (pfindData->
1625                                                       FileNameLength) / 2,
1626                                                      cifs_sb->local_nls);
1627                                         qstring.len = pfindData->FileNameLength;
1628                                         if (((qstring.len != 1)
1629                                              || (pfindData->FileName[0] != '.'))
1630                                             && ((qstring.len != 2)
1631                                                 || (pfindData->
1632                                                     FileName[0] != '.')
1633                                                 || (pfindData->
1634                                                     FileName[1] != '.'))) {
1635                                                 if(cifs_filldir(&qstring,
1636                                                              pfindData,
1637                                                              file, filldir,
1638                                                              direntry)) {
1639                                                         /* do not end search if
1640                                                                 kernel not ready to take
1641                                                                 remaining entries yet */
1642                                                         reset_resume_key(file, pfindData->FileName,qstring.len,
1643                                                                 Unicode, cifs_sb->local_nls);
1644                                                         findParms.EndofSearch = 0;
1645                                                         break;
1646                                                 }
1647                                                 file->f_pos++;
1648                                         }
1649                                 } else {        /* UnixSearch */
1650                                         pfindDataUnix =
1651                                             (FILE_UNIX_INFO *) pfindData;
1652                                         if (Unicode == TRUE)
1653                                                 qstring.len =
1654                                                         cifs_strfromUCS_le
1655                                                         (pfindDataUnix->FileName,
1656                                                         (wchar_t *)
1657                                                         pfindDataUnix->FileName,
1658                                                         MAX_PATHCONF,
1659                                                         cifs_sb->local_nls);
1660                                         else
1661                                                 qstring.len =
1662                                                         strnlen(pfindDataUnix->
1663                                                           FileName,
1664                                                           MAX_PATHCONF);
1665                                         if (((qstring.len != 1)
1666                                              || (pfindDataUnix->
1667                                                  FileName[0] != '.'))
1668                                             && ((qstring.len != 2)
1669                                                 || (pfindDataUnix->
1670                                                     FileName[0] != '.')
1671                                                 || (pfindDataUnix->
1672                                                     FileName[1] != '.'))) {
1673                                                 if(cifs_filldir_unix(&qstring,
1674                                                                   pfindDataUnix,
1675                                                                   file,
1676                                                                   filldir,
1677                                                                   direntry)) {
1678                                                         /* do not end search if
1679                                                                 kernel not ready to take
1680                                                                 remaining entries yet */
1681                                                         findParms.EndofSearch = 0;
1682                                                         reset_resume_key(file, pfindDataUnix->FileName,
1683                                                                 qstring.len,Unicode,cifs_sb->local_nls);
1684                                                         break;
1685                                                 }
1686                                                 file->f_pos++;
1687                                         }
1688                                 }
1689                                 /* works also for Unix ff struct since first field of both */
1690                                 pfindData = 
1691                                         (FILE_DIRECTORY_INFO *) ((char *) pfindData
1692                                                  + le32_to_cpu(pfindData->NextEntryOffset));
1693                                 /* BB also should check to make sure that pointer is not beyond the end of the SMB */
1694                                 /* if(pfindData > lastFindData) rc = -EIO; break; */
1695                         }       /* end for loop */
1696                         if ((findParms.EndofSearch != 0) && cifsFile) {
1697                                 cifsFile->endOfSearch = TRUE;
1698                                 if(findParms.SearchCount == 2)
1699                                         cifsFile->emptyDir = TRUE;
1700                         }
1701                 } else {
1702                         if (cifsFile)
1703                                 cifsFile->endOfSearch = TRUE;
1704                         /* unless parent directory gone do not return error */
1705                         rc = 0;
1706                 }
1707                 break;
1708         default:
1709                 if (file->private_data == NULL) {
1710                         rc = -EBADF;
1711                         cFYI(1,
1712                              ("Readdir on closed srch, pos = %lld",
1713                               file->f_pos));
1714                 } else {
1715                         cifsFile = (struct cifsFileInfo *) file->private_data;
1716                         if (cifsFile->endOfSearch) {
1717                                 rc = 0;
1718                                 cFYI(1, ("End of search "));
1719                                 break;
1720                         }
1721                         searchHandle = cifsFile->netfid;
1722                         rc = CIFSFindNext(xid, pTcon, pfindData,
1723                                 &findNextParms, searchHandle, 
1724                                 cifsFile->search_resume_name,
1725                                 cifsFile->resume_name_length,
1726                                 cifsFile->resume_key,
1727                                 &Unicode, &UnixSearch);
1728                         cFYI(1,("Count: %d  End: %d ",
1729                               findNextParms.SearchCount,
1730                               findNextParms.EndofSearch));
1731                         if ((rc == 0) && (findNextParms.SearchCount != 0)) {
1732                         /* BB save off resume key, key name and name length  */
1733                                 lastFindData = 
1734                                         (FILE_DIRECTORY_INFO *) ((char *) pfindData 
1735                                                 + findNextParms.LastNameOffset);
1736                                 if((char *)lastFindData > (char *)pfindData + bufsize) {
1737                                         cFYI(1,("last search entry past end of packet"));
1738                                         rc = -EIO;
1739                                         break;
1740                                 }
1741                                 /* Offset of resume key same for levels 257 and 514 */
1742                                 cifsFile->resume_key = lastFindData->FileIndex;
1743
1744                                 if(UnixSearch == FALSE) {
1745                                         cifsFile->resume_name_length = 
1746                                                 le32_to_cpu(lastFindData->FileNameLength);
1747                                         if(cifsFile->resume_name_length > bufsize - 64) {
1748                                                 cFYI(1,("Illegal resume file name length %d",
1749                                                         cifsFile->resume_name_length));
1750                                                 rc = -ENOMEM;
1751                                                 break;
1752                                         }
1753                                         /* Free the memory allocated by previous findfirst 
1754                                         or findnext call - we can not reuse the memory since
1755                                         the resume name may not be same string length */
1756                                         if(cifsFile->search_resume_name)
1757                                                 kfree(cifsFile->search_resume_name);
1758                                         cifsFile->search_resume_name = 
1759                                                 kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
1760                                         cFYI(1,("Last file: %s with name %d bytes long",
1761                                                 lastFindData->FileName,
1762                                                 cifsFile->resume_name_length));
1763                                         memcpy(cifsFile->search_resume_name,
1764                                                 lastFindData->FileName, 
1765                                                 cifsFile->resume_name_length);
1766                                 } else {
1767                                         pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
1768                                         if (Unicode == TRUE) {
1769                                                 for(i=0;(pfindDataUnix->FileName[i] 
1770                                                                 | pfindDataUnix->FileName[i+1]);
1771                                                         i+=2) {
1772                                                         if(i > bufsize-64)
1773                                                                 break;
1774                                                 }
1775                                                 cifsFile->resume_name_length = i + 2;
1776                                         } else {
1777                                                 cifsFile->resume_name_length = 
1778                                                         strnlen(pfindDataUnix->
1779                                                          FileName,
1780                                                          MAX_PATHCONF);
1781                                         }
1782                                         if(cifsFile->resume_name_length > bufsize - 64) {
1783                                                 cFYI(1,("Illegal resume file name length %d",
1784                                                                 cifsFile->resume_name_length));
1785                                                 rc = -ENOMEM;
1786                                                 break;
1787                                         }
1788                                         /* Free the memory allocated by previous findfirst 
1789                                         or findnext call - we can not reuse the memory since
1790                                         the resume name may not be same string length */
1791                                         if(cifsFile->search_resume_name)
1792                                                 kfree(cifsFile->search_resume_name);
1793                                         cifsFile->search_resume_name = 
1794                                                 kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
1795                                         cFYI(1,("fnext last file: %s with name %d bytes long",
1796                                                 lastFindData->FileName,
1797                                                 cifsFile->resume_name_length));
1798                                         memcpy(cifsFile->search_resume_name,
1799                                                 lastFindData->FileName, 
1800                                                 cifsFile->resume_name_length);
1801                                 }
1802
1803                                 for (i = 0; i < findNextParms.SearchCount; i++) {
1804                                         pfindData->FileNameLength =
1805                                             le32_to_cpu(pfindData->
1806                                                         FileNameLength);
1807                                         if (UnixSearch == FALSE) {
1808                                                 if (Unicode == TRUE)
1809                                                         pfindData->FileNameLength =
1810                                                           cifs_strfromUCS_le
1811                                                           (pfindData->FileName,
1812                                                           (wchar_t *)
1813                                                           pfindData->FileName,
1814                                                           (pfindData->FileNameLength)/ 2,
1815                                                           cifs_sb->local_nls);
1816                                                 qstring.len = 
1817                                                         pfindData->FileNameLength;
1818                                                 if (((qstring.len != 1)
1819                                                     || (pfindData->FileName[0] != '.'))
1820                                                     && ((qstring.len != 2)
1821                                                         || (pfindData->FileName[0] != '.')
1822                                                         || (pfindData->FileName[1] !=
1823                                                             '.'))) {
1824                                                         if(cifs_filldir
1825                                                             (&qstring,
1826                                                              pfindData,
1827                                                              file, filldir,
1828                                                              direntry)) {
1829                                                         /* do not end search if
1830                                                                 kernel not ready to take
1831                                                                 remaining entries yet */
1832                                                                 findNextParms.EndofSearch = 0;
1833                                                                 reset_resume_key(file, pfindData->FileName,qstring.len,
1834                                                                         Unicode,cifs_sb->local_nls);
1835                                                                 break;
1836                                                         }
1837                                                         file->f_pos++;
1838                                                 }
1839                                         } else {        /* UnixSearch */
1840                                                 pfindDataUnix =
1841                                                     (FILE_UNIX_INFO *)
1842                                                     pfindData;
1843                                                 if (Unicode == TRUE)
1844                                                         qstring.len =
1845                                                           cifs_strfromUCS_le
1846                                                           (pfindDataUnix->FileName,
1847                                                           (wchar_t *)
1848                                                           pfindDataUnix->FileName,
1849                                                           MAX_PATHCONF,
1850                                                           cifs_sb->local_nls);
1851                                                 else
1852                                                         qstring.len =
1853                                                           strnlen
1854                                                           (pfindDataUnix->
1855                                                           FileName,
1856                                                           MAX_PATHCONF);
1857                                                 if (((qstring.len != 1)
1858                                                      || (pfindDataUnix->
1859                                                          FileName[0] != '.'))
1860                                                     && ((qstring.len != 2)
1861                                                         || (pfindDataUnix->
1862                                                             FileName[0] != '.')
1863                                                         || (pfindDataUnix->
1864                                                             FileName[1] !=
1865                                                             '.'))) {
1866                                                         if(cifs_filldir_unix
1867                                                             (&qstring,
1868                                                              pfindDataUnix,
1869                                                              file, filldir,
1870                                                              direntry)) {
1871                                                                 /* do not end search if
1872                                                                 kernel not ready to take
1873                                                                 remaining entries yet */
1874                                                                 findNextParms.EndofSearch = 0;
1875                                                                 reset_resume_key(file, pfindDataUnix->FileName,qstring.len,
1876                                                                         Unicode,cifs_sb->local_nls);
1877                                                                 break;
1878                                                         }
1879                                                         file->f_pos++;
1880                                                 }
1881                                         }
1882                                         pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + 
1883                                                 le32_to_cpu(pfindData->NextEntryOffset));
1884         /* works also for Unix find struct since first field of both */
1885         /* BB also should check to ensure pointer not beyond end of SMB */
1886                                 } /* end for loop */
1887                                 if (findNextParms.EndofSearch != 0) {
1888                                         cifsFile->endOfSearch = TRUE;
1889                                 }
1890                         } else {
1891                                 cifsFile->endOfSearch = TRUE;
1892                                 rc = 0; /* unless parent directory disappeared - do not
1893                                 return error here (eg Access Denied or no more files) */
1894                         }
1895                 }
1896         } /* end switch */
1897         if (data)
1898                 kfree(data);
1899         if (full_path)
1900                 kfree(full_path);
1901         FreeXid(xid);
1902
1903         return rc;
1904 }
1905 int cifs_prepare_write(struct file *file, struct page *page,
1906                         unsigned from, unsigned to)
1907 {
1908         cFYI(1,("prepare write for page %p from %d to %d",page,from,to));
1909         if (!PageUptodate(page)) {
1910                 if (to - from != PAGE_CACHE_SIZE) {
1911                         void *kaddr = kmap_atomic(page, KM_USER0);
1912                         memset(kaddr, 0, from);
1913                         memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
1914                         flush_dcache_page(page);
1915                         kunmap_atomic(kaddr, KM_USER0);
1916                 }
1917                 SetPageUptodate(page);
1918         }
1919         return 0;
1920 }
1921
1922
1923 struct address_space_operations cifs_addr_ops = {
1924         .readpage = cifs_readpage,
1925         .readpages = cifs_readpages,
1926         .writepage = cifs_writepage,
1927         .prepare_write = simple_prepare_write, /* BB fixme BB */
1928 /*      .prepare_write = cifs_prepare_write, */  /* BB removeme BB */
1929         .commit_write = cifs_commit_write,
1930    /* .sync_page = cifs_sync_page, */
1931         /*.direct_IO = */
1932 };