linux/fs/cifs/readdir.c
<<
>>
Prefs
   1/*
   2 *   fs/cifs/readdir.c
   3 *
   4 *   Directory search handling
   5 *
   6 *   Copyright (C) International Business Machines  Corp., 2004, 2008
   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/pagemap.h>
  25#include <linux/stat.h>
  26#include "cifspdu.h"
  27#include "cifsglob.h"
  28#include "cifsproto.h"
  29#include "cifs_unicode.h"
  30#include "cifs_debug.h"
  31#include "cifs_fs_sb.h"
  32#include "cifsfs.h"
  33
  34#ifdef CONFIG_CIFS_DEBUG2
  35static void dump_cifs_file_struct(struct file *file, char *label)
  36{
  37        struct cifsFileInfo *cf;
  38
  39        if (file) {
  40                cf = file->private_data;
  41                if (cf == NULL) {
  42                        cFYI(1, ("empty cifs private file data"));
  43                        return;
  44                }
  45                if (cf->invalidHandle)
  46                        cFYI(1, ("invalid handle"));
  47                if (cf->srch_inf.endOfSearch)
  48                        cFYI(1, ("end of search"));
  49                if (cf->srch_inf.emptyDir)
  50                        cFYI(1, ("empty dir"));
  51        }
  52}
  53#else
  54static inline void dump_cifs_file_struct(struct file *file, char *label)
  55{
  56}
  57#endif /* DEBUG2 */
  58
  59/* Returns one if new inode created (which therefore needs to be hashed) */
  60/* Might check in the future if inode number changed so we can rehash inode */
  61static int construct_dentry(struct qstr *qstring, struct file *file,
  62        struct inode **ptmp_inode, struct dentry **pnew_dentry)
  63{
  64        struct dentry *tmp_dentry;
  65        struct cifs_sb_info *cifs_sb;
  66        struct cifsTconInfo *pTcon;
  67        int rc = 0;
  68
  69        cFYI(1, ("For %s", qstring->name));
  70        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
  71        pTcon = cifs_sb->tcon;
  72
  73        qstring->hash = full_name_hash(qstring->name, qstring->len);
  74        tmp_dentry = d_lookup(file->f_path.dentry, qstring);
  75        if (tmp_dentry) {
  76                cFYI(0, ("existing dentry with inode 0x%p",
  77                         tmp_dentry->d_inode));
  78                *ptmp_inode = tmp_dentry->d_inode;
  79/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
  80                if (*ptmp_inode == NULL) {
  81                        *ptmp_inode = new_inode(file->f_path.dentry->d_sb);
  82                        if (*ptmp_inode == NULL)
  83                                return rc;
  84                        rc = 1;
  85                }
  86                if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
  87                        (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
  88        } else {
  89                tmp_dentry = d_alloc(file->f_path.dentry, qstring);
  90                if (tmp_dentry == NULL) {
  91                        cERROR(1, ("Failed allocating dentry"));
  92                        *ptmp_inode = NULL;
  93                        return rc;
  94                }
  95
  96                *ptmp_inode = new_inode(file->f_path.dentry->d_sb);
  97                if (pTcon->nocase)
  98                        tmp_dentry->d_op = &cifs_ci_dentry_ops;
  99                else
 100                        tmp_dentry->d_op = &cifs_dentry_ops;
 101                if (*ptmp_inode == NULL)
 102                        return rc;
 103                if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
 104                        (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
 105                rc = 2;
 106        }
 107
 108        tmp_dentry->d_time = jiffies;
 109        *pnew_dentry = tmp_dentry;
 110        return rc;
 111}
 112
 113static void AdjustForTZ(struct cifsTconInfo *tcon, struct inode *inode)
 114{
 115        if ((tcon) && (tcon->ses) && (tcon->ses->server)) {
 116                inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
 117                inode->i_mtime.tv_sec += tcon->ses->server->timeAdj;
 118                inode->i_atime.tv_sec += tcon->ses->server->timeAdj;
 119        }
 120        return;
 121}
 122
 123
 124static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
 125                          char *buf, unsigned int *pobject_type, int isNewInode)
 126{
 127        loff_t local_size;
 128        struct timespec local_mtime;
 129
 130        struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
 131        struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
 132        __u32 attr;
 133        __u64 allocation_size;
 134        __u64 end_of_file;
 135        umode_t default_mode;
 136
 137        /* save mtime and size */
 138        local_mtime = tmp_inode->i_mtime;
 139        local_size  = tmp_inode->i_size;
 140
 141        if (new_buf_type) {
 142                FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
 143
 144                attr = le32_to_cpu(pfindData->ExtFileAttributes);
 145                allocation_size = le64_to_cpu(pfindData->AllocationSize);
 146                end_of_file = le64_to_cpu(pfindData->EndOfFile);
 147                tmp_inode->i_atime =
 148                      cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
 149                tmp_inode->i_mtime =
 150                      cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
 151                tmp_inode->i_ctime =
 152                      cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
 153        } else { /* legacy, OS2 and DOS style */
 154/*              struct timespec ts;*/
 155                FIND_FILE_STANDARD_INFO *pfindData =
 156                        (FIND_FILE_STANDARD_INFO *)buf;
 157
 158                tmp_inode->i_mtime = cnvrtDosUnixTm(
 159                                le16_to_cpu(pfindData->LastWriteDate),
 160                                le16_to_cpu(pfindData->LastWriteTime));
 161                tmp_inode->i_atime = cnvrtDosUnixTm(
 162                                le16_to_cpu(pfindData->LastAccessDate),
 163                                le16_to_cpu(pfindData->LastAccessTime));
 164                tmp_inode->i_ctime = cnvrtDosUnixTm(
 165                                le16_to_cpu(pfindData->LastWriteDate),
 166                                le16_to_cpu(pfindData->LastWriteTime));
 167                AdjustForTZ(cifs_sb->tcon, tmp_inode);
 168                attr = le16_to_cpu(pfindData->Attributes);
 169                allocation_size = le32_to_cpu(pfindData->AllocationSize);
 170                end_of_file = le32_to_cpu(pfindData->DataSize);
 171        }
 172
 173        /* Linux can not store file creation time unfortunately so ignore it */
 174
 175        cifsInfo->cifsAttrs = attr;
 176#ifdef CONFIG_CIFS_EXPERIMENTAL
 177        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
 178                /* get more accurate mode via ACL - so force inode refresh */
 179                cifsInfo->time = 0;
 180        } else
 181#endif /* CONFIG_CIFS_EXPERIMENTAL */
 182                cifsInfo->time = jiffies;
 183
 184        /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
 185        /* 2767 perms - indicate mandatory locking */
 186                /* BB fill in uid and gid here? with help from winbind?
 187                   or retrieve from NTFS stream extended attribute */
 188        if (atomic_read(&cifsInfo->inUse) == 0) {
 189                tmp_inode->i_uid = cifs_sb->mnt_uid;
 190                tmp_inode->i_gid = cifs_sb->mnt_gid;
 191        }
 192
 193        if (attr & ATTR_DIRECTORY)
 194                default_mode = cifs_sb->mnt_dir_mode;
 195        else
 196                default_mode = cifs_sb->mnt_file_mode;
 197
 198        /* set initial permissions */
 199        if ((atomic_read(&cifsInfo->inUse) == 0) ||
 200            (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
 201                tmp_inode->i_mode = default_mode;
 202        else {
 203                /* just reenable write bits if !ATTR_READONLY */
 204                if ((tmp_inode->i_mode & S_IWUGO) == 0 &&
 205                    (attr & ATTR_READONLY) == 0)
 206                        tmp_inode->i_mode |= (S_IWUGO & default_mode);
 207
 208                tmp_inode->i_mode &= ~S_IFMT;
 209        }
 210
 211        /* clear write bits if ATTR_READONLY is set */
 212        if (attr & ATTR_READONLY)
 213                tmp_inode->i_mode &= ~S_IWUGO;
 214
 215        /* set inode type */
 216        if ((attr & ATTR_SYSTEM) &&
 217            (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
 218                if (end_of_file == 0)  {
 219                        tmp_inode->i_mode |= S_IFIFO;
 220                        *pobject_type = DT_FIFO;
 221                } else {
 222                        /*
 223                         * trying to get the type can be slow, so just call
 224                         * this a regular file for now, and mark for reval
 225                         */
 226                        tmp_inode->i_mode |= S_IFREG;
 227                        *pobject_type = DT_REG;
 228                        cifsInfo->time = 0;
 229                }
 230        } else {
 231                if (attr & ATTR_DIRECTORY) {
 232                        tmp_inode->i_mode |= S_IFDIR;
 233                        *pobject_type = DT_DIR;
 234                } else {
 235                        tmp_inode->i_mode |= S_IFREG;
 236                        *pobject_type = DT_REG;
 237                }
 238        }
 239
 240        /* can not fill in nlink here as in qpathinfo version and Unx search */
 241        if (atomic_read(&cifsInfo->inUse) == 0)
 242                atomic_set(&cifsInfo->inUse, 1);
 243
 244        spin_lock(&tmp_inode->i_lock);
 245        if (is_size_safe_to_change(cifsInfo, end_of_file)) {
 246                /* can not safely change the file size here if the
 247                client is writing to it due to potential races */
 248                i_size_write(tmp_inode, end_of_file);
 249
 250        /* 512 bytes (2**9) is the fake blocksize that must be used */
 251        /* for this calculation, even though the reported blocksize is larger */
 252                tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
 253        }
 254        spin_unlock(&tmp_inode->i_lock);
 255
 256        if (allocation_size < end_of_file)
 257                cFYI(1, ("May be sparse file, allocation less than file size"));
 258        cFYI(1, ("File Size %ld and blocks %llu",
 259                (unsigned long)tmp_inode->i_size,
 260                (unsigned long long)tmp_inode->i_blocks));
 261        if (S_ISREG(tmp_inode->i_mode)) {
 262                cFYI(1, ("File inode"));
 263                tmp_inode->i_op = &cifs_file_inode_ops;
 264                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
 265                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 266                                tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
 267                        else
 268                                tmp_inode->i_fop = &cifs_file_direct_ops;
 269                } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 270                        tmp_inode->i_fop = &cifs_file_nobrl_ops;
 271                else
 272                        tmp_inode->i_fop = &cifs_file_ops;
 273
 274                if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
 275                   (cifs_sb->tcon->ses->server->maxBuf <
 276                        PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
 277                        tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
 278                else
 279                        tmp_inode->i_data.a_ops = &cifs_addr_ops;
 280
 281                if (isNewInode)
 282                        return; /* No sense invalidating pages for new inode
 283                                   since have not started caching readahead file
 284                                   data yet */
 285
 286                if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
 287                        (local_size == tmp_inode->i_size)) {
 288                        cFYI(1, ("inode exists but unchanged"));
 289                } else {
 290                        /* file may have changed on server */
 291                        cFYI(1, ("invalidate inode, readdir detected change"));
 292                        invalidate_remote_inode(tmp_inode);
 293                }
 294        } else if (S_ISDIR(tmp_inode->i_mode)) {
 295                cFYI(1, ("Directory inode"));
 296                tmp_inode->i_op = &cifs_dir_inode_ops;
 297                tmp_inode->i_fop = &cifs_dir_ops;
 298        } else if (S_ISLNK(tmp_inode->i_mode)) {
 299                cFYI(1, ("Symbolic Link inode"));
 300                tmp_inode->i_op = &cifs_symlink_inode_ops;
 301        } else {
 302                cFYI(1, ("Init special inode"));
 303                init_special_inode(tmp_inode, tmp_inode->i_mode,
 304                                   tmp_inode->i_rdev);
 305        }
 306}
 307
 308static void unix_fill_in_inode(struct inode *tmp_inode,
 309        FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode)
 310{
 311        loff_t local_size;
 312        struct timespec local_mtime;
 313
 314        struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
 315        struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
 316
 317        __u32 type = le32_to_cpu(pfindData->Type);
 318        __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
 319        __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
 320        cifsInfo->time = jiffies;
 321        atomic_inc(&cifsInfo->inUse);
 322
 323        /* save mtime and size */
 324        local_mtime = tmp_inode->i_mtime;
 325        local_size  = tmp_inode->i_size;
 326
 327        tmp_inode->i_atime =
 328            cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
 329        tmp_inode->i_mtime =
 330            cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
 331        tmp_inode->i_ctime =
 332            cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));
 333
 334        tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
 335        /* since we set the inode type below we need to mask off type
 336           to avoid strange results if bits above were corrupt */
 337        tmp_inode->i_mode &= ~S_IFMT;
 338        if (type == UNIX_FILE) {
 339                *pobject_type = DT_REG;
 340                tmp_inode->i_mode |= S_IFREG;
 341        } else if (type == UNIX_SYMLINK) {
 342                *pobject_type = DT_LNK;
 343                tmp_inode->i_mode |= S_IFLNK;
 344        } else if (type == UNIX_DIR) {
 345                *pobject_type = DT_DIR;
 346                tmp_inode->i_mode |= S_IFDIR;
 347        } else if (type == UNIX_CHARDEV) {
 348                *pobject_type = DT_CHR;
 349                tmp_inode->i_mode |= S_IFCHR;
 350                tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
 351                                le64_to_cpu(pfindData->DevMinor) & MINORMASK);
 352        } else if (type == UNIX_BLOCKDEV) {
 353                *pobject_type = DT_BLK;
 354                tmp_inode->i_mode |= S_IFBLK;
 355                tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
 356                                le64_to_cpu(pfindData->DevMinor) & MINORMASK);
 357        } else if (type == UNIX_FIFO) {
 358                *pobject_type = DT_FIFO;
 359                tmp_inode->i_mode |= S_IFIFO;
 360        } else if (type == UNIX_SOCKET) {
 361                *pobject_type = DT_SOCK;
 362                tmp_inode->i_mode |= S_IFSOCK;
 363        } else {
 364                /* safest to just call it a file */
 365                *pobject_type = DT_REG;
 366                tmp_inode->i_mode |= S_IFREG;
 367                cFYI(1, ("unknown inode type %d", type));
 368        }
 369
 370        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
 371                tmp_inode->i_uid = cifs_sb->mnt_uid;
 372        else
 373                tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
 374        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
 375                tmp_inode->i_gid = cifs_sb->mnt_gid;
 376        else
 377                tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
 378        tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
 379
 380        spin_lock(&tmp_inode->i_lock);
 381        if (is_size_safe_to_change(cifsInfo, end_of_file)) {
 382                /* can not safely change the file size here if the
 383                client is writing to it due to potential races */
 384                i_size_write(tmp_inode, end_of_file);
 385
 386        /* 512 bytes (2**9) is the fake blocksize that must be used */
 387        /* for this calculation, not the real blocksize */
 388                tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
 389        }
 390        spin_unlock(&tmp_inode->i_lock);
 391
 392        if (S_ISREG(tmp_inode->i_mode)) {
 393                cFYI(1, ("File inode"));
 394                tmp_inode->i_op = &cifs_file_inode_ops;
 395
 396                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
 397                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 398                                tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
 399                        else
 400                                tmp_inode->i_fop = &cifs_file_direct_ops;
 401                } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 402                        tmp_inode->i_fop = &cifs_file_nobrl_ops;
 403                else
 404                        tmp_inode->i_fop = &cifs_file_ops;
 405
 406                if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
 407                   (cifs_sb->tcon->ses->server->maxBuf <
 408                        PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
 409                        tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
 410                else
 411                        tmp_inode->i_data.a_ops = &cifs_addr_ops;
 412
 413                if (isNewInode)
 414                        return; /* No sense invalidating pages for new inode
 415                                   since we have not started caching readahead
 416                                   file data for it yet */
 417
 418                if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
 419                        (local_size == tmp_inode->i_size)) {
 420                        cFYI(1, ("inode exists but unchanged"));
 421                } else {
 422                        /* file may have changed on server */
 423                        cFYI(1, ("invalidate inode, readdir detected change"));
 424                        invalidate_remote_inode(tmp_inode);
 425                }
 426        } else if (S_ISDIR(tmp_inode->i_mode)) {
 427                cFYI(1, ("Directory inode"));
 428                tmp_inode->i_op = &cifs_dir_inode_ops;
 429                tmp_inode->i_fop = &cifs_dir_ops;
 430        } else if (S_ISLNK(tmp_inode->i_mode)) {
 431                cFYI(1, ("Symbolic Link inode"));
 432                tmp_inode->i_op = &cifs_symlink_inode_ops;
 433/* tmp_inode->i_fop = *//* do not need to set to anything */
 434        } else {
 435                cFYI(1, ("Special inode"));
 436                init_special_inode(tmp_inode, tmp_inode->i_mode,
 437                                   tmp_inode->i_rdev);
 438        }
 439}
 440
 441static int initiate_cifs_search(const int xid, struct file *file)
 442{
 443        int rc = 0;
 444        char *full_path;
 445        struct cifsFileInfo *cifsFile;
 446        struct cifs_sb_info *cifs_sb;
 447        struct cifsTconInfo *pTcon;
 448
 449        if (file->private_data == NULL) {
 450                file->private_data =
 451                        kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
 452        }
 453
 454        if (file->private_data == NULL)
 455                return -ENOMEM;
 456        cifsFile = file->private_data;
 457        cifsFile->invalidHandle = true;
 458        cifsFile->srch_inf.endOfSearch = false;
 459
 460        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 461        if (cifs_sb == NULL)
 462                return -EINVAL;
 463
 464        pTcon = cifs_sb->tcon;
 465        if (pTcon == NULL)
 466                return -EINVAL;
 467
 468        full_path = build_path_from_dentry(file->f_path.dentry);
 469
 470        if (full_path == NULL)
 471                return -ENOMEM;
 472
 473        cFYI(1, ("Full path: %s start at: %lld", full_path, file->f_pos));
 474
 475ffirst_retry:
 476        /* test for Unix extensions */
 477        /* but now check for them on the share/mount not on the SMB session */
 478/*      if (pTcon->ses->capabilities & CAP_UNIX) { */
 479        if (pTcon->unix_ext)
 480                cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
 481        else if ((pTcon->ses->capabilities &
 482                        (CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
 483                cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
 484        } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
 485                cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
 486        } else /* not srvinos - BB fixme add check for backlevel? */ {
 487                cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
 488        }
 489
 490        rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
 491                &cifsFile->netfid, &cifsFile->srch_inf,
 492                cifs_sb->mnt_cifs_flags &
 493                        CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
 494        if (rc == 0)
 495                cifsFile->invalidHandle = false;
 496        if ((rc == -EOPNOTSUPP) &&
 497                (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
 498                cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
 499                goto ffirst_retry;
 500        }
 501        kfree(full_path);
 502        return rc;
 503}
 504
 505/* return length of unicode string in bytes */
 506static int cifs_unicode_bytelen(char *str)
 507{
 508        int len;
 509        __le16 *ustr = (__le16 *)str;
 510
 511        for (len = 0; len <= PATH_MAX; len++) {
 512                if (ustr[len] == 0)
 513                        return len << 1;
 514        }
 515        cFYI(1, ("Unicode string longer than PATH_MAX found"));
 516        return len << 1;
 517}
 518
 519static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
 520{
 521        char *new_entry;
 522        FILE_DIRECTORY_INFO *pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
 523
 524        if (level == SMB_FIND_FILE_INFO_STANDARD) {
 525                FIND_FILE_STANDARD_INFO *pfData;
 526                pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
 527
 528                new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) +
 529                                pfData->FileNameLength;
 530        } else
 531                new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
 532        cFYI(1, ("new entry %p old entry %p", new_entry, old_entry));
 533        /* validate that new_entry is not past end of SMB */
 534        if (new_entry >= end_of_smb) {
 535                cERROR(1,
 536                      ("search entry %p began after end of SMB %p old entry %p",
 537                        new_entry, end_of_smb, old_entry));
 538                return NULL;
 539        } else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
 540                    (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
 541                  || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
 542                   (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
 543                cERROR(1, ("search entry %p extends after end of SMB %p",
 544                        new_entry, end_of_smb));
 545                return NULL;
 546        } else
 547                return new_entry;
 548
 549}
 550
 551#define UNICODE_DOT cpu_to_le16(0x2e)
 552
 553/* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */
 554static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
 555{
 556        int rc = 0;
 557        char *filename = NULL;
 558        int len = 0;
 559
 560        if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
 561                FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
 562                filename = &pFindData->FileName[0];
 563                if (cfile->srch_inf.unicode) {
 564                        len = cifs_unicode_bytelen(filename);
 565                } else {
 566                        /* BB should we make this strnlen of PATH_MAX? */
 567                        len = strnlen(filename, 5);
 568                }
 569        } else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
 570                FILE_DIRECTORY_INFO *pFindData =
 571                        (FILE_DIRECTORY_INFO *)current_entry;
 572                filename = &pFindData->FileName[0];
 573                len = le32_to_cpu(pFindData->FileNameLength);
 574        } else if (cfile->srch_inf.info_level ==
 575                        SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
 576                FILE_FULL_DIRECTORY_INFO *pFindData =
 577                        (FILE_FULL_DIRECTORY_INFO *)current_entry;
 578                filename = &pFindData->FileName[0];
 579                len = le32_to_cpu(pFindData->FileNameLength);
 580        } else if (cfile->srch_inf.info_level ==
 581                        SMB_FIND_FILE_ID_FULL_DIR_INFO) {
 582                SEARCH_ID_FULL_DIR_INFO *pFindData =
 583                        (SEARCH_ID_FULL_DIR_INFO *)current_entry;
 584                filename = &pFindData->FileName[0];
 585                len = le32_to_cpu(pFindData->FileNameLength);
 586        } else if (cfile->srch_inf.info_level ==
 587                        SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
 588                FILE_BOTH_DIRECTORY_INFO *pFindData =
 589                        (FILE_BOTH_DIRECTORY_INFO *)current_entry;
 590                filename = &pFindData->FileName[0];
 591                len = le32_to_cpu(pFindData->FileNameLength);
 592        } else if (cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
 593                FIND_FILE_STANDARD_INFO *pFindData =
 594                        (FIND_FILE_STANDARD_INFO *)current_entry;
 595                filename = &pFindData->FileName[0];
 596                len = pFindData->FileNameLength;
 597        } else {
 598                cFYI(1, ("Unknown findfirst level %d",
 599                         cfile->srch_inf.info_level));
 600        }
 601
 602        if (filename) {
 603                if (cfile->srch_inf.unicode) {
 604                        __le16 *ufilename = (__le16 *)filename;
 605                        if (len == 2) {
 606                                /* check for . */
 607                                if (ufilename[0] == UNICODE_DOT)
 608                                        rc = 1;
 609                        } else if (len == 4) {
 610                                /* check for .. */
 611                                if ((ufilename[0] == UNICODE_DOT)
 612                                   && (ufilename[1] == UNICODE_DOT))
 613                                        rc = 2;
 614                        }
 615                } else /* ASCII */ {
 616                        if (len == 1) {
 617                                if (filename[0] == '.')
 618                                        rc = 1;
 619                        } else if (len == 2) {
 620                                if ((filename[0] == '.') && (filename[1] == '.'))
 621                                        rc = 2;
 622                        }
 623                }
 624        }
 625
 626        return rc;
 627}
 628
 629/* Check if directory that we are searching has changed so we can decide
 630   whether we can use the cached search results from the previous search */
 631static int is_dir_changed(struct file *file)
 632{
 633        struct inode *inode = file->f_path.dentry->d_inode;
 634        struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
 635
 636        if (cifsInfo->time == 0)
 637                return 1; /* directory was changed, perhaps due to unlink */
 638        else
 639                return 0;
 640
 641}
 642
 643static int cifs_save_resume_key(const char *current_entry,
 644        struct cifsFileInfo *cifsFile)
 645{
 646        int rc = 0;
 647        unsigned int len = 0;
 648        __u16 level;
 649        char *filename;
 650
 651        if ((cifsFile == NULL) || (current_entry == NULL))
 652                return -EINVAL;
 653
 654        level = cifsFile->srch_inf.info_level;
 655
 656        if (level == SMB_FIND_FILE_UNIX) {
 657                FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
 658
 659                filename = &pFindData->FileName[0];
 660                if (cifsFile->srch_inf.unicode) {
 661                        len = cifs_unicode_bytelen(filename);
 662                } else {
 663                        /* BB should we make this strnlen of PATH_MAX? */
 664                        len = strnlen(filename, PATH_MAX);
 665                }
 666                cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
 667        } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
 668                FILE_DIRECTORY_INFO *pFindData =
 669                        (FILE_DIRECTORY_INFO *)current_entry;
 670                filename = &pFindData->FileName[0];
 671                len = le32_to_cpu(pFindData->FileNameLength);
 672                cifsFile->srch_inf.resume_key = pFindData->FileIndex;
 673        } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
 674                FILE_FULL_DIRECTORY_INFO *pFindData =
 675                        (FILE_FULL_DIRECTORY_INFO *)current_entry;
 676                filename = &pFindData->FileName[0];
 677                len = le32_to_cpu(pFindData->FileNameLength);
 678                cifsFile->srch_inf.resume_key = pFindData->FileIndex;
 679        } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
 680                SEARCH_ID_FULL_DIR_INFO *pFindData =
 681                        (SEARCH_ID_FULL_DIR_INFO *)current_entry;
 682                filename = &pFindData->FileName[0];
 683                len = le32_to_cpu(pFindData->FileNameLength);
 684                cifsFile->srch_inf.resume_key = pFindData->FileIndex;
 685        } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
 686                FILE_BOTH_DIRECTORY_INFO *pFindData =
 687                        (FILE_BOTH_DIRECTORY_INFO *)current_entry;
 688                filename = &pFindData->FileName[0];
 689                len = le32_to_cpu(pFindData->FileNameLength);
 690                cifsFile->srch_inf.resume_key = pFindData->FileIndex;
 691        } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
 692                FIND_FILE_STANDARD_INFO *pFindData =
 693                        (FIND_FILE_STANDARD_INFO *)current_entry;
 694                filename = &pFindData->FileName[0];
 695                /* one byte length, no name conversion */
 696                len = (unsigned int)pFindData->FileNameLength;
 697                cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
 698        } else {
 699                cFYI(1, ("Unknown findfirst level %d", level));
 700                return -EINVAL;
 701        }
 702        cifsFile->srch_inf.resume_name_len = len;
 703        cifsFile->srch_inf.presume_name = filename;
 704        return rc;
 705}
 706
 707/* find the corresponding entry in the search */
 708/* Note that the SMB server returns search entries for . and .. which
 709   complicates logic here if we choose to parse for them and we do not
 710   assume that they are located in the findfirst return buffer.*/
 711/* We start counting in the buffer with entry 2 and increment for every
 712   entry (do not increment for . or .. entry) */
 713static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 714        struct file *file, char **ppCurrentEntry, int *num_to_ret)
 715{
 716        int rc = 0;
 717        int pos_in_buf = 0;
 718        loff_t first_entry_in_buffer;
 719        loff_t index_to_find = file->f_pos;
 720        struct cifsFileInfo *cifsFile = file->private_data;
 721        /* check if index in the buffer */
 722
 723        if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
 724           (num_to_ret == NULL))
 725                return -ENOENT;
 726
 727        *ppCurrentEntry = NULL;
 728        first_entry_in_buffer =
 729                cifsFile->srch_inf.index_of_last_entry -
 730                        cifsFile->srch_inf.entries_in_buffer;
 731
 732        /* if first entry in buf is zero then is first buffer
 733        in search response data which means it is likely . and ..
 734        will be in this buffer, although some servers do not return
 735        . and .. for the root of a drive and for those we need
 736        to start two entries earlier */
 737
 738        dump_cifs_file_struct(file, "In fce ");
 739        if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
 740             is_dir_changed(file)) ||
 741           (index_to_find < first_entry_in_buffer)) {
 742                /* close and restart search */
 743                cFYI(1, ("search backing up - close and restart search"));
 744                write_lock(&GlobalSMBSeslock);
 745                if (!cifsFile->srch_inf.endOfSearch &&
 746                    !cifsFile->invalidHandle) {
 747                        cifsFile->invalidHandle = true;
 748                        write_unlock(&GlobalSMBSeslock);
 749                        CIFSFindClose(xid, pTcon, cifsFile->netfid);
 750                } else
 751                        write_unlock(&GlobalSMBSeslock);
 752                if (cifsFile->srch_inf.ntwrk_buf_start) {
 753                        cFYI(1, ("freeing SMB ff cache buf on search rewind"));
 754                        if (cifsFile->srch_inf.smallBuf)
 755                                cifs_small_buf_release(cifsFile->srch_inf.
 756                                                ntwrk_buf_start);
 757                        else
 758                                cifs_buf_release(cifsFile->srch_inf.
 759                                                ntwrk_buf_start);
 760                        cifsFile->srch_inf.ntwrk_buf_start = NULL;
 761                }
 762                rc = initiate_cifs_search(xid, file);
 763                if (rc) {
 764                        cFYI(1, ("error %d reinitiating a search on rewind",
 765                                 rc));
 766                        return rc;
 767                }
 768                cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
 769        }
 770
 771        while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
 772              (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
 773                cFYI(1, ("calling findnext2"));
 774                rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
 775                                  &cifsFile->srch_inf);
 776                cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
 777                if (rc)
 778                        return -ENOENT;
 779        }
 780        if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
 781                /* we found the buffer that contains the entry */
 782                /* scan and find it */
 783                int i;
 784                char *current_entry;
 785                char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
 786                        smbCalcSize((struct smb_hdr *)
 787                                cifsFile->srch_inf.ntwrk_buf_start);
 788
 789                current_entry = cifsFile->srch_inf.srch_entries_start;
 790                first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
 791                                        - cifsFile->srch_inf.entries_in_buffer;
 792                pos_in_buf = index_to_find - first_entry_in_buffer;
 793                cFYI(1, ("found entry - pos_in_buf %d", pos_in_buf));
 794
 795                for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
 796                        /* go entry by entry figuring out which is first */
 797                        current_entry = nxt_dir_entry(current_entry, end_of_smb,
 798                                                cifsFile->srch_inf.info_level);
 799                }
 800                if ((current_entry == NULL) && (i < pos_in_buf)) {
 801                        /* BB fixme - check if we should flag this error */
 802                        cERROR(1, ("reached end of buf searching for pos in buf"
 803                          " %d index to find %lld rc %d",
 804                          pos_in_buf, index_to_find, rc));
 805                }
 806                rc = 0;
 807                *ppCurrentEntry = current_entry;
 808        } else {
 809                cFYI(1, ("index not in buffer - could not findnext into it"));
 810                return 0;
 811        }
 812
 813        if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
 814                cFYI(1, ("can not return entries pos_in_buf beyond last"));
 815                *num_to_ret = 0;
 816        } else
 817                *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
 818
 819        return rc;
 820}
 821
 822/* inode num, inode type and filename returned */
 823static int cifs_get_name_from_search_buf(struct qstr *pqst,
 824        char *current_entry, __u16 level, unsigned int unicode,
 825        struct cifs_sb_info *cifs_sb, int max_len, ino_t *pinum)
 826{
 827        int rc = 0;
 828        unsigned int len = 0;
 829        char *filename;
 830        struct nls_table *nlt = cifs_sb->local_nls;
 831
 832        *pinum = 0;
 833
 834        if (level == SMB_FIND_FILE_UNIX) {
 835                FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
 836
 837                filename = &pFindData->FileName[0];
 838                if (unicode) {
 839                        len = cifs_unicode_bytelen(filename);
 840                } else {
 841                        /* BB should we make this strnlen of PATH_MAX? */
 842                        len = strnlen(filename, PATH_MAX);
 843                }
 844
 845                /* BB fixme - hash low and high 32 bits if not 64 bit arch BB */
 846                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
 847                        *pinum = pFindData->UniqueId;
 848        } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
 849                FILE_DIRECTORY_INFO *pFindData =
 850                        (FILE_DIRECTORY_INFO *)current_entry;
 851                filename = &pFindData->FileName[0];
 852                len = le32_to_cpu(pFindData->FileNameLength);
 853        } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
 854                FILE_FULL_DIRECTORY_INFO *pFindData =
 855                        (FILE_FULL_DIRECTORY_INFO *)current_entry;
 856                filename = &pFindData->FileName[0];
 857                len = le32_to_cpu(pFindData->FileNameLength);
 858        } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
 859                SEARCH_ID_FULL_DIR_INFO *pFindData =
 860                        (SEARCH_ID_FULL_DIR_INFO *)current_entry;
 861                filename = &pFindData->FileName[0];
 862                len = le32_to_cpu(pFindData->FileNameLength);
 863                *pinum = pFindData->UniqueId;
 864        } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
 865                FILE_BOTH_DIRECTORY_INFO *pFindData =
 866                        (FILE_BOTH_DIRECTORY_INFO *)current_entry;
 867                filename = &pFindData->FileName[0];
 868                len = le32_to_cpu(pFindData->FileNameLength);
 869        } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
 870                FIND_FILE_STANDARD_INFO *pFindData =
 871                        (FIND_FILE_STANDARD_INFO *)current_entry;
 872                filename = &pFindData->FileName[0];
 873                /* one byte length, no name conversion */
 874                len = (unsigned int)pFindData->FileNameLength;
 875        } else {
 876                cFYI(1, ("Unknown findfirst level %d", level));
 877                return -EINVAL;
 878        }
 879
 880        if (len > max_len) {
 881                cERROR(1, ("bad search response length %d past smb end", len));
 882                return -EINVAL;
 883        }
 884
 885        if (unicode) {
 886                /* BB fixme - test with long names */
 887                /* Note converted filename can be longer than in unicode */
 888                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
 889                        pqst->len = cifs_convertUCSpath((char *)pqst->name,
 890                                        (__le16 *)filename, len/2, nlt);
 891                else
 892                        pqst->len = cifs_strfromUCS_le((char *)pqst->name,
 893                                        (__le16 *)filename, len/2, nlt);
 894        } else {
 895                pqst->name = filename;
 896                pqst->len = len;
 897        }
 898        pqst->hash = full_name_hash(pqst->name, pqst->len);
 899/*      cFYI(1, ("filldir on %s",pqst->name));  */
 900        return rc;
 901}
 902
 903static int cifs_filldir(char *pfindEntry, struct file *file,
 904        filldir_t filldir, void *direntry, char *scratch_buf, int max_len)
 905{
 906        int rc = 0;
 907        struct qstr qstring;
 908        struct cifsFileInfo *pCifsF;
 909        unsigned int obj_type;
 910        ino_t  inum;
 911        struct cifs_sb_info *cifs_sb;
 912        struct inode *tmp_inode;
 913        struct dentry *tmp_dentry;
 914
 915        /* get filename and len into qstring */
 916        /* get dentry */
 917        /* decide whether to create and populate ionde */
 918        if ((direntry == NULL) || (file == NULL))
 919                return -EINVAL;
 920
 921        pCifsF = file->private_data;
 922
 923        if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
 924                return -ENOENT;
 925
 926        rc = cifs_entry_is_dot(pfindEntry, pCifsF);
 927        /* skip . and .. since we added them first */
 928        if (rc != 0)
 929                return 0;
 930
 931        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 932
 933        qstring.name = scratch_buf;
 934        rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
 935                        pCifsF->srch_inf.info_level,
 936                        pCifsF->srch_inf.unicode, cifs_sb,
 937                        max_len,
 938                        &inum /* returned */);
 939
 940        if (rc)
 941                return rc;
 942
 943        rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry);
 944        if ((tmp_inode == NULL) || (tmp_dentry == NULL))
 945                return -ENOMEM;
 946
 947        if (rc) {
 948                /* inode created, we need to hash it with right inode number */
 949                if (inum != 0) {
 950                        /* BB fixme - hash the 2 32 quantities bits together if
 951                         *  necessary BB */
 952                        tmp_inode->i_ino = inum;
 953                }
 954                insert_inode_hash(tmp_inode);
 955        }
 956
 957        /* we pass in rc below, indicating whether it is a new inode,
 958           so we can figure out whether to invalidate the inode cached
 959           data if the file has changed */
 960        if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
 961                unix_fill_in_inode(tmp_inode,
 962                                   (FILE_UNIX_INFO *)pfindEntry,
 963                                   &obj_type, rc);
 964        else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
 965                fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
 966                                pfindEntry, &obj_type, rc);
 967        else
 968                fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
 969
 970        if (rc) /* new inode - needs to be tied to dentry */ {
 971                d_instantiate(tmp_dentry, tmp_inode);
 972                if (rc == 2)
 973                        d_rehash(tmp_dentry);
 974        }
 975
 976
 977        rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
 978                     tmp_inode->i_ino, obj_type);
 979        if (rc) {
 980                cFYI(1, ("filldir rc = %d", rc));
 981                /* we can not return filldir errors to the caller
 982                since they are "normal" when the stat blocksize
 983                is too small - we return remapped error instead */
 984                rc = -EOVERFLOW;
 985        }
 986
 987        dput(tmp_dentry);
 988        return rc;
 989}
 990
 991
 992int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 993{
 994        int rc = 0;
 995        int xid, i;
 996        struct cifs_sb_info *cifs_sb;
 997        struct cifsTconInfo *pTcon;
 998        struct cifsFileInfo *cifsFile = NULL;
 999        char *current_entry;
1000        int num_to_fill = 0;
1001        char *tmp_buf = NULL;
1002        char *end_of_smb;
1003        int max_len;
1004
1005        xid = GetXid();
1006
1007        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
1008        pTcon = cifs_sb->tcon;
1009        if (pTcon == NULL)
1010                return -EINVAL;
1011
1012        switch ((int) file->f_pos) {
1013        case 0:
1014                if (filldir(direntry, ".", 1, file->f_pos,
1015                     file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) {
1016                        cERROR(1, ("Filldir for current dir failed"));
1017                        rc = -ENOMEM;
1018                        break;
1019                }
1020                file->f_pos++;
1021        case 1:
1022                if (filldir(direntry, "..", 2, file->f_pos,
1023                     file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
1024                        cERROR(1, ("Filldir for parent dir failed"));
1025                        rc = -ENOMEM;
1026                        break;
1027                }
1028                file->f_pos++;
1029        default:
1030                /* 1) If search is active,
1031                        is in current search buffer?
1032                        if it before then restart search
1033                        if after then keep searching till find it */
1034
1035                if (file->private_data == NULL) {
1036                        rc = initiate_cifs_search(xid, file);
1037                        cFYI(1, ("initiate cifs search rc %d", rc));
1038                        if (rc) {
1039                                FreeXid(xid);
1040                                return rc;
1041                        }
1042                }
1043                if (file->private_data == NULL) {
1044                        rc = -EINVAL;
1045                        FreeXid(xid);
1046                        return rc;
1047                }
1048                cifsFile = file->private_data;
1049                if (cifsFile->srch_inf.endOfSearch) {
1050                        if (cifsFile->srch_inf.emptyDir) {
1051                                cFYI(1, ("End of search, empty dir"));
1052                                rc = 0;
1053                                break;
1054                        }
1055                } /* else {
1056                        cifsFile->invalidHandle = true;
1057                        CIFSFindClose(xid, pTcon, cifsFile->netfid);
1058                } */
1059
1060                rc = find_cifs_entry(xid, pTcon, file,
1061                                &current_entry, &num_to_fill);
1062                if (rc) {
1063                        cFYI(1, ("fce error %d", rc));
1064                        goto rddir2_exit;
1065                } else if (current_entry != NULL) {
1066                        cFYI(1, ("entry %lld found", file->f_pos));
1067                } else {
1068                        cFYI(1, ("could not find entry"));
1069                        goto rddir2_exit;
1070                }
1071                cFYI(1, ("loop through %d times filling dir for net buf %p",
1072                        num_to_fill, cifsFile->srch_inf.ntwrk_buf_start));
1073                max_len = smbCalcSize((struct smb_hdr *)
1074                                cifsFile->srch_inf.ntwrk_buf_start);
1075                end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
1076
1077                /* To be safe - for UCS to UTF-8 with strings loaded
1078                with the rare long characters alloc more to account for
1079                such multibyte target UTF-8 characters. cifs_unicode.c,
1080                which actually does the conversion, has the same limit */
1081                tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL);
1082                for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
1083                        if (current_entry == NULL) {
1084                                /* evaluate whether this case is an error */
1085                                cERROR(1, ("past SMB end,  num to fill %d i %d",
1086                                          num_to_fill, i));
1087                                break;
1088                        }
1089                        /* if buggy server returns . and .. late do
1090                        we want to check for that here? */
1091                        rc = cifs_filldir(current_entry, file,
1092                                        filldir, direntry, tmp_buf, max_len);
1093                        if (rc == -EOVERFLOW) {
1094                                rc = 0;
1095                                break;
1096                        }
1097
1098                        file->f_pos++;
1099                        if (file->f_pos ==
1100                                cifsFile->srch_inf.index_of_last_entry) {
1101                                cFYI(1, ("last entry in buf at pos %lld %s",
1102                                        file->f_pos, tmp_buf));
1103                                cifs_save_resume_key(current_entry, cifsFile);
1104                                break;
1105                        } else
1106                                current_entry =
1107                                        nxt_dir_entry(current_entry, end_of_smb,
1108                                                cifsFile->srch_inf.info_level);
1109                }
1110                kfree(tmp_buf);
1111                break;
1112        } /* end switch */
1113
1114rddir2_exit:
1115        FreeXid(xid);
1116        return rc;
1117}
1118
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.