Blame view
fs/cifs/readdir.c
29.9 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 |
/* * fs/cifs/readdir.c * * Directory search handling |
6dc0f87e3 [CIFS] whitespace... |
5 |
* |
ad7a2926b [CIFS] reduce che... |
6 |
* Copyright (C) International Business Machines Corp., 2004, 2008 |
cda0ec6a8 cifs: introduce c... |
7 |
* Copyright (C) Red Hat, Inc., 2011 |
1da177e4c Linux-2.6.12-rc2 |
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
* Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/fs.h> |
273d81d6a [CIFS] Do not ove... |
25 |
#include <linux/pagemap.h> |
5a0e3ad6a include cleanup: ... |
26 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
27 |
#include <linux/stat.h> |
1da177e4c Linux-2.6.12-rc2 |
28 29 30 31 32 33 34 |
#include "cifspdu.h" #include "cifsglob.h" #include "cifsproto.h" #include "cifs_unicode.h" #include "cifs_debug.h" #include "cifs_fs_sb.h" #include "cifsfs.h" |
3d519bd12 cifs: plumb smb2 ... |
35 |
#include "smb2proto.h" |
1da177e4c Linux-2.6.12-rc2 |
36 |
|
f58841666 cifs: change cifs... |
37 38 39 40 41 42 |
/* * To be safe - for UCS to UTF-8 with strings loaded with the rare long * characters alloc more to account for such multibyte target UTF-8 * characters. */ #define UNICODE_NAME_MAX ((4 * NAME_MAX) + 2) |
3979877e5 [CIFS] Support fo... |
43 44 |
#ifdef CONFIG_CIFS_DEBUG2 static void dump_cifs_file_struct(struct file *file, char *label) |
1da177e4c Linux-2.6.12-rc2 |
45 |
{ |
6dc0f87e3 [CIFS] whitespace... |
46 |
struct cifsFileInfo *cf; |
1da177e4c Linux-2.6.12-rc2 |
47 |
|
4523cc304 [CIFS] UID/GID ov... |
48 |
if (file) { |
1da177e4c Linux-2.6.12-rc2 |
49 |
cf = file->private_data; |
4523cc304 [CIFS] UID/GID ov... |
50 |
if (cf == NULL) { |
f96637be0 [CIFS] cifs: Rena... |
51 52 |
cifs_dbg(FYI, "empty cifs private file data "); |
1da177e4c Linux-2.6.12-rc2 |
53 54 |
return; } |
ad7a2926b [CIFS] reduce che... |
55 |
if (cf->invalidHandle) |
a0a3036b8 cifs: Standardize... |
56 57 |
cifs_dbg(FYI, "Invalid handle "); |
ad7a2926b [CIFS] reduce che... |
58 |
if (cf->srch_inf.endOfSearch) |
f96637be0 [CIFS] cifs: Rena... |
59 60 |
cifs_dbg(FYI, "end of search "); |
ad7a2926b [CIFS] reduce che... |
61 |
if (cf->srch_inf.emptyDir) |
f96637be0 [CIFS] cifs: Rena... |
62 63 |
cifs_dbg(FYI, "empty dir "); |
1da177e4c Linux-2.6.12-rc2 |
64 |
} |
3979877e5 [CIFS] Support fo... |
65 |
} |
90c81e0b0 [CIFS] clean up s... |
66 67 68 69 |
#else static inline void dump_cifs_file_struct(struct file *file, char *label) { } |
3979877e5 [CIFS] Support fo... |
70 |
#endif /* DEBUG2 */ |
1da177e4c Linux-2.6.12-rc2 |
71 |
|
cc0bad755 cifs: add new cif... |
72 |
/* |
eb1b3fa5c cifs: rename cifs... |
73 74 |
* Attempt to preload the dcache with the results from the FIND_FIRST/NEXT * |
cc0bad755 cifs: add new cif... |
75 |
* Find the dentry that matches "name". If there isn't one, create one. If it's |
9e6d722f3 cifs: make new in... |
76 77 |
* a negative dentry or the uniqueid or filetype(mode) changed, * then drop it and recreate it. |
cc0bad755 cifs: add new cif... |
78 |
*/ |
eb1b3fa5c cifs: rename cifs... |
79 80 |
static void cifs_prime_dcache(struct dentry *parent, struct qstr *name, |
cc0bad755 cifs: add new cif... |
81 82 83 84 |
struct cifs_fattr *fattr) { struct dentry *dentry, *alias; struct inode *inode; |
fc64005c9 don't bother with... |
85 |
struct super_block *sb = parent->d_sb; |
2f2591a34 cifs: don't compa... |
86 |
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
3125d2650 cifs: switch to -... |
87 |
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); |
cc0bad755 cifs: add new cif... |
88 |
|
f96637be0 [CIFS] cifs: Rena... |
89 90 |
cifs_dbg(FYI, "%s: for %s ", __func__, name->name); |
cc0bad755 cifs: add new cif... |
91 |
|
4f522a247 d_hash_and_lookup... |
92 |
dentry = d_hash_and_lookup(parent, name); |
3125d2650 cifs: switch to -... |
93 94 95 96 97 98 99 100 101 102 103 104 |
if (!dentry) { /* * If we know that the inode will need to be revalidated * immediately, then don't create a new dentry for it. * We'll end up doing an on the wire call either way and * this spares us an invalidation. */ if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL) return; retry: dentry = d_alloc_parallel(parent, name, &wq); } |
a1c83681d fs: Drop unlikely... |
105 |
if (IS_ERR(dentry)) |
4f522a247 d_hash_and_lookup... |
106 |
return; |
3125d2650 cifs: switch to -... |
107 |
if (!d_in_lookup(dentry)) { |
2b0143b5c VFS: normal files... |
108 |
inode = d_inode(dentry); |
2f2591a34 cifs: don't compa... |
109 |
if (inode) { |
3125d2650 cifs: switch to -... |
110 111 112 113 |
if (d_mountpoint(dentry)) { dput(dentry); return; } |
2f2591a34 cifs: don't compa... |
114 115 116 117 118 119 120 |
/* * If we're generating inode numbers, then we don't * want to clobber the existing one with the one that * the readdir code created. */ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) fattr->cf_uniqueid = CIFS_I(inode)->uniqueid; |
9e6d722f3 cifs: make new in... |
121 122 123 124 125 |
/* update inode in place * if both i_ino and i_mode didn't change */ if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid && (inode->i_mode & S_IFMT) == (fattr->cf_mode & S_IFMT)) { |
2f2591a34 cifs: don't compa... |
126 |
cifs_fattr_to_inode(inode, fattr); |
3125d2650 cifs: switch to -... |
127 128 |
dput(dentry); return; |
2f2591a34 cifs: don't compa... |
129 |
} |
cd60042cc cifs: always upda... |
130 |
} |
5542aa2fa vfs: Make d_inval... |
131 |
d_invalidate(dentry); |
cc0bad755 cifs: add new cif... |
132 |
dput(dentry); |
3125d2650 cifs: switch to -... |
133 134 135 136 137 138 139 140 141 |
goto retry; } else { inode = cifs_iget(sb, fattr); if (!inode) inode = ERR_PTR(-ENOMEM); alias = d_splice_alias(inode, dentry); d_lookup_done(dentry); if (alias && !IS_ERR(alias)) dput(alias); |
cc0bad755 cifs: add new cif... |
142 |
} |
eb1b3fa5c cifs: rename cifs... |
143 |
dput(dentry); |
cc0bad755 cifs: add new cif... |
144 |
} |
046aca3c2 cifs: Optimize re... |
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
static bool reparse_file_needs_reval(const struct cifs_fattr *fattr) { if (!(fattr->cf_cifsattrs & ATTR_REPARSE)) return false; /* * The DFS tags should be only intepreted by server side as per * MS-FSCC 2.1.2.1, but let's include them anyway. * * Besides, if cf_cifstag is unset (0), then we still need it to be * revalidated to know exactly what reparse point it is. */ switch (fattr->cf_cifstag) { case IO_REPARSE_TAG_DFS: case IO_REPARSE_TAG_DFSR: case IO_REPARSE_TAG_SYMLINK: case IO_REPARSE_TAG_NFS: case 0: return true; } return false; } |
0b8f18e35 cifs: convert cif... |
166 167 |
static void cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) |
1da177e4c Linux-2.6.12-rc2 |
168 |
{ |
0b8f18e35 cifs: convert cif... |
169 170 |
fattr->cf_uid = cifs_sb->mnt_uid; fattr->cf_gid = cifs_sb->mnt_gid; |
1da177e4c Linux-2.6.12-rc2 |
171 |
|
13909d96c SMB3: add support... |
172 173 174 175 176 177 178 179 |
/* * The IO_REPARSE_TAG_LX_ tags originally were used by WSL but they * are preferred by the Linux client in some cases since, unlike * the NFS reparse tag (or EAs), they don't require an extra query * to determine which type of special file they represent. * TODO: go through all documented reparse tags to see if we can * reasonably map some of them to directories vs. files vs. symlinks */ |
0b8f18e35 cifs: convert cif... |
180 181 182 |
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; fattr->cf_dtype = DT_DIR; |
13909d96c SMB3: add support... |
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_SYMLINK) { fattr->cf_mode |= S_IFLNK | cifs_sb->mnt_file_mode; fattr->cf_dtype = DT_LNK; } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_FIFO) { fattr->cf_mode |= S_IFIFO | cifs_sb->mnt_file_mode; fattr->cf_dtype = DT_FIFO; } else if (fattr->cf_cifstag == IO_REPARSE_TAG_AF_UNIX) { fattr->cf_mode |= S_IFSOCK | cifs_sb->mnt_file_mode; fattr->cf_dtype = DT_SOCK; } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_CHR) { fattr->cf_mode |= S_IFCHR | cifs_sb->mnt_file_mode; fattr->cf_dtype = DT_CHR; } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_BLK) { fattr->cf_mode |= S_IFBLK | cifs_sb->mnt_file_mode; fattr->cf_dtype = DT_BLK; } else { /* TODO: should we mark some other reparse points (like DFSR) as directories? */ |
0b8f18e35 cifs: convert cif... |
199 200 |
fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; fattr->cf_dtype = DT_REG; |
1da177e4c Linux-2.6.12-rc2 |
201 |
} |
eb85d94bd CIFS: Fix symboli... |
202 203 204 205 206 |
/* * We need to revalidate it further to make a decision about whether it * is a symbolic link, DFS referral or a reparse point with a direct * access like junctions, deduplicated files, NFS symlinks. */ |
046aca3c2 cifs: Optimize re... |
207 |
if (reparse_file_needs_reval(fattr)) |
eb85d94bd CIFS: Fix symboli... |
208 |
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; |
74d290da4 [CIFS] Provide sa... |
209 210 |
/* non-unix readdir doesn't provide nlink */ fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; |
0b8f18e35 cifs: convert cif... |
211 212 |
if (fattr->cf_cifsattrs & ATTR_READONLY) fattr->cf_mode &= ~S_IWUGO; |
5bafd7659 [CIFS] Add suppor... |
213 |
|
ccb5c001b cifs: ensure we r... |
214 215 216 217 218 219 220 |
/* * We of course don't get ACL info in FIND_FIRST/NEXT results, so * mark it for revalidation so that "ls -l" will look right. It might * be super-slow, but if we don't do this then the ownership of files * may look wrong since the inodes may not have timed out by the time * "ls" does a stat() call on them. */ |
e3e056c35 cifs: fix mode bi... |
221 222 |
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) |
ccb5c001b cifs: ensure we r... |
223 |
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; |
0b8f18e35 cifs: convert cif... |
224 225 226 227 228 229 |
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL && fattr->cf_cifsattrs & ATTR_SYSTEM) { if (fattr->cf_eof == 0) { fattr->cf_mode &= ~S_IFMT; fattr->cf_mode |= S_IFIFO; fattr->cf_dtype = DT_FIFO; |
3020a1f58 [CIFS] Fix schedu... |
230 |
} else { |
4468eb3fd on non-posix shar... |
231 |
/* |
0b8f18e35 cifs: convert cif... |
232 233 234 |
* trying to get the type and mode via SFU can be slow, * so just call those regular files for now, and mark * for reval |
4468eb3fd on non-posix shar... |
235 |
*/ |
0b8f18e35 cifs: convert cif... |
236 |
fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; |
4468eb3fd on non-posix shar... |
237 238 |
} } |
0b8f18e35 cifs: convert cif... |
239 |
} |
1da177e4c Linux-2.6.12-rc2 |
240 |
|
3d519bd12 cifs: plumb smb2 ... |
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
/* Fill a cifs_fattr struct with info from SMB_FIND_FILE_POSIX_INFO. */ static void cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info, struct cifs_sb_info *cifs_sb) { struct smb2_posix_info_parsed parsed; posix_info_parse(info, NULL, &parsed); memset(fattr, 0, sizeof(*fattr)); fattr->cf_uniqueid = le64_to_cpu(info->Inode); fattr->cf_bytes = le64_to_cpu(info->AllocationSize); fattr->cf_eof = le64_to_cpu(info->EndOfFile); fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); fattr->cf_ctime = cifs_NTtimeToUnix(info->CreationTime); fattr->cf_nlink = le32_to_cpu(info->HardLinks); fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); /* * Since we set the inode type below we need to mask off * to avoid strange results if bits set above. * XXX: why not make server&client use the type bits? */ fattr->cf_mode = le32_to_cpu(info->Mode) & ~S_IFMT; |
a0a3036b8 cifs: Standardize... |
268 269 |
cifs_dbg(FYI, "posix fattr: dev %d, reparse %d, mode %o ", |
3d519bd12 cifs: plumb smb2 ... |
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
le32_to_cpu(info->DeviceId), le32_to_cpu(info->ReparseTag), le32_to_cpu(info->Mode)); if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { fattr->cf_mode |= S_IFDIR; fattr->cf_dtype = DT_DIR; } else { /* * mark anything that is not a dir as regular * file. special files should have the REPARSE * attribute and will be marked as needing revaluation */ fattr->cf_mode |= S_IFREG; fattr->cf_dtype = DT_REG; } if (reparse_file_needs_reval(fattr)) fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; |
9934430e2 SMB3.1.1: Fix ids... |
289 290 |
sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER); sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP); |
3d519bd12 cifs: plumb smb2 ... |
291 |
} |
046aca3c2 cifs: Optimize re... |
292 293 294 295 296 297 298 299 300 301 302 303 304 |
static void __dir_info_to_fattr(struct cifs_fattr *fattr, const void *info) { const FILE_DIRECTORY_INFO *fi = info; memset(fattr, 0, sizeof(*fattr)); fattr->cf_cifsattrs = le32_to_cpu(fi->ExtFileAttributes); fattr->cf_eof = le64_to_cpu(fi->EndOfFile); fattr->cf_bytes = le64_to_cpu(fi->AllocationSize); fattr->cf_createtime = le64_to_cpu(fi->CreationTime); fattr->cf_atime = cifs_NTtimeToUnix(fi->LastAccessTime); fattr->cf_ctime = cifs_NTtimeToUnix(fi->ChangeTime); fattr->cf_mtime = cifs_NTtimeToUnix(fi->LastWriteTime); } |
c052e2b42 cifs: obtain file... |
305 |
void |
0b8f18e35 cifs: convert cif... |
306 307 308 |
cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info, struct cifs_sb_info *cifs_sb) { |
046aca3c2 cifs: Optimize re... |
309 310 311 |
__dir_info_to_fattr(fattr, info); cifs_fill_common_info(fattr, cifs_sb); } |
0b8f18e35 cifs: convert cif... |
312 |
|
046aca3c2 cifs: Optimize re... |
313 314 315 316 317 318 319 320 321 |
static void cifs_fulldir_info_to_fattr(struct cifs_fattr *fattr, SEARCH_ID_FULL_DIR_INFO *info, struct cifs_sb_info *cifs_sb) { __dir_info_to_fattr(fattr, info); /* See MS-FSCC 2.4.18 FileIdFullDirectoryInformation */ if (fattr->cf_cifsattrs & ATTR_REPARSE) fattr->cf_cifstag = le32_to_cpu(info->EaSize); |
0b8f18e35 cifs: convert cif... |
322 323 |
cifs_fill_common_info(fattr, cifs_sb); } |
1da177e4c Linux-2.6.12-rc2 |
324 |
|
15dd47810 [CIFS] Remove bui... |
325 |
static void |
0b8f18e35 cifs: convert cif... |
326 327 328 |
cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, struct cifs_sb_info *cifs_sb) { |
0d424ad0a cifs: add cifs_sb... |
329 |
int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj; |
1da177e4c Linux-2.6.12-rc2 |
330 |
|
0b8f18e35 cifs: convert cif... |
331 332 333 334 335 336 337 338 339 340 341 342 343 |
memset(fattr, 0, sizeof(*fattr)); fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, info->LastAccessTime, offset); fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate, info->LastWriteTime, offset); fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate, info->LastWriteTime, offset); fattr->cf_cifsattrs = le16_to_cpu(info->Attributes); fattr->cf_bytes = le32_to_cpu(info->AllocationSize); fattr->cf_eof = le32_to_cpu(info->DataSize); cifs_fill_common_info(fattr, cifs_sb); |
1da177e4c Linux-2.6.12-rc2 |
344 |
} |
0e0d2cf32 [CIFS] Remove spa... |
345 346 347 348 349 |
/* BB eventually need to add the following helper function to resolve NT_STATUS_STOPPED_ON_SYMLINK return code when we try to do FindFirst on (NTFS) directory symlinks */ /* int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, |
6d5786a34 CIFS: Rename Get/... |
350 |
unsigned int xid) |
0e0d2cf32 [CIFS] Remove spa... |
351 352 353 354 355 |
{ __u16 fid; int len; int oplock = 0; int rc; |
96daf2b09 [CIFS] Rename thr... |
356 |
struct cifs_tcon *ptcon = cifs_sb_tcon(cifs_sb); |
0e0d2cf32 [CIFS] Remove spa... |
357 358 359 360 361 |
char *tmpbuffer; rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, OPEN_REPARSE_POINT, &fid, &oplock, NULL, cifs_sb->local_nls, |
2baa26825 Remap reserved po... |
362 |
cifs_remap(cifs_sb); |
0e0d2cf32 [CIFS] Remove spa... |
363 364 365 366 367 368 369 370 |
if (!rc) { tmpbuffer = kmalloc(maxpath); rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path, tmpbuffer, maxpath -1, fid, cifs_sb->local_nls); if (CIFSSMBClose(xid, ptcon, fid)) { |
f96637be0 [CIFS] cifs: Rena... |
371 372 |
cifs_dbg(FYI, "Error closing temporary reparsepoint open "); |
0e0d2cf32 [CIFS] Remove spa... |
373 374 375 376 |
} } } */ |
92fc65a74 CIFS: Move readdi... |
377 |
static int |
d1542cf61 cifs: compute ful... |
378 379 |
initiate_cifs_search(const unsigned int xid, struct file *file, char *full_path) |
1da177e4c Linux-2.6.12-rc2 |
380 |
{ |
2608bee74 cifs: Include bac... |
381 |
__u16 search_flags; |
1da177e4c Linux-2.6.12-rc2 |
382 |
int rc = 0; |
3870253ef [CIFS] more white... |
383 |
struct cifsFileInfo *cifsFile; |
7119e220a cifs: get rid of ... |
384 |
struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file); |
59c55ba1f cifs: don't take ... |
385 |
struct tcon_link *tlink = NULL; |
29e20f9c6 CIFS: Make CAP_* ... |
386 |
struct cifs_tcon *tcon; |
92fc65a74 CIFS: Move readdi... |
387 |
struct TCP_Server_Info *server; |
1da177e4c Linux-2.6.12-rc2 |
388 |
|
7ffec3724 cifs: add refcoun... |
389 |
if (file->private_data == NULL) { |
59c55ba1f cifs: don't take ... |
390 391 392 393 394 395 396 397 398 |
tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); if (cifsFile == NULL) { rc = -ENOMEM; goto error_exit; } |
81ddd8c0c cifs: initialize ... |
399 |
spin_lock_init(&cifsFile->file_info_lock); |
59c55ba1f cifs: don't take ... |
400 401 |
file->private_data = cifsFile; cifsFile->tlink = cifs_get_tlink(tlink); |
29e20f9c6 CIFS: Make CAP_* ... |
402 |
tcon = tlink_tcon(tlink); |
59c55ba1f cifs: don't take ... |
403 404 |
} else { cifsFile = file->private_data; |
29e20f9c6 CIFS: Make CAP_* ... |
405 |
tcon = tlink_tcon(cifsFile->tlink); |
7ffec3724 cifs: add refcoun... |
406 |
} |
1da177e4c Linux-2.6.12-rc2 |
407 |
|
92fc65a74 CIFS: Move readdi... |
408 409 410 411 412 413 |
server = tcon->ses->server; if (!server->ops->query_dir_first) { rc = -ENOSYS; goto error_exit; } |
4b18f2a9c [CIFS] convert us... |
414 415 |
cifsFile->invalidHandle = true; cifsFile->srch_inf.endOfSearch = false; |
1da177e4c Linux-2.6.12-rc2 |
416 |
|
f96637be0 [CIFS] cifs: Rena... |
417 418 |
cifs_dbg(FYI, "Full path: %s start at: %lld ", full_path, file->f_pos); |
1da177e4c Linux-2.6.12-rc2 |
419 |
|
75cf6bdc5 [PATCH] cifs: Gra... |
420 |
ffirst_retry: |
1da177e4c Linux-2.6.12-rc2 |
421 |
/* test for Unix extensions */ |
c18c842b1 [CIFS] Allow disa... |
422 |
/* but now check for them on the share/mount not on the SMB session */ |
29e20f9c6 CIFS: Make CAP_* ... |
423 424 |
/* if (cap_unix(tcon->ses) { */ if (tcon->unix_ext) |
5bafd7659 [CIFS] Add suppor... |
425 |
cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; |
3d519bd12 cifs: plumb smb2 ... |
426 427 |
else if (tcon->posix_extensions) cifsFile->srch_inf.info_level = SMB_FIND_FILE_POSIX_INFO; |
29e20f9c6 CIFS: Make CAP_* ... |
428 429 |
else if ((tcon->ses->capabilities & tcon->ses->server->vals->cap_nt_find) == 0) { |
5bafd7659 [CIFS] Add suppor... |
430 |
cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD; |
1da177e4c Linux-2.6.12-rc2 |
431 432 433 434 435 |
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; } else /* not srvinos - BB fixme add check for backlevel? */ { cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; } |
2608bee74 cifs: Include bac... |
436 437 438 |
search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; if (backup_cred(cifs_sb)) search_flags |= CIFS_SEARCH_BACKUP_SEARCH; |
92fc65a74 CIFS: Move readdi... |
439 440 441 |
rc = server->ops->query_dir_first(xid, tcon, full_path, cifs_sb, &cifsFile->fid, search_flags, &cifsFile->srch_inf); |
4523cc304 [CIFS] UID/GID ov... |
442 |
if (rc == 0) |
4b18f2a9c [CIFS] convert us... |
443 |
cifsFile->invalidHandle = false; |
e836f015b [CIFS] Remove tra... |
444 |
/* BB add following call to handle readdir on new NTFS symlink errors |
0e0d2cf32 [CIFS] Remove spa... |
445 446 447 |
else if STATUS_STOPPED_ON_SYMLINK call get_symlink_reparse_path and retry with new path */ else if ((rc == -EOPNOTSUPP) && |
75cf6bdc5 [PATCH] cifs: Gra... |
448 449 450 451 |
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; goto ffirst_retry; } |
7ffec3724 cifs: add refcoun... |
452 |
error_exit: |
7ffec3724 cifs: add refcoun... |
453 |
cifs_put_tlink(tlink); |
1da177e4c Linux-2.6.12-rc2 |
454 455 456 457 |
return rc; } /* return length of unicode string in bytes */ |
cda0ec6a8 cifs: introduce c... |
458 |
static int cifs_unicode_bytelen(const char *str) |
1da177e4c Linux-2.6.12-rc2 |
459 460 |
{ int len; |
cda0ec6a8 cifs: introduce c... |
461 |
const __le16 *ustr = (const __le16 *)str; |
1da177e4c Linux-2.6.12-rc2 |
462 |
|
3870253ef [CIFS] more white... |
463 |
for (len = 0; len <= PATH_MAX; len++) { |
4523cc304 [CIFS] UID/GID ov... |
464 |
if (ustr[len] == 0) |
1da177e4c Linux-2.6.12-rc2 |
465 466 |
return len << 1; } |
f96637be0 [CIFS] cifs: Rena... |
467 468 |
cifs_dbg(FYI, "Unicode string longer than PATH_MAX found "); |
1da177e4c Linux-2.6.12-rc2 |
469 470 |
return len << 1; } |
5bafd7659 [CIFS] Add suppor... |
471 |
static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) |
1da177e4c Linux-2.6.12-rc2 |
472 |
{ |
3870253ef [CIFS] more white... |
473 |
char *new_entry; |
ad7a2926b [CIFS] reduce che... |
474 |
FILE_DIRECTORY_INFO *pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; |
1da177e4c Linux-2.6.12-rc2 |
475 |
|
4523cc304 [CIFS] UID/GID ov... |
476 |
if (level == SMB_FIND_FILE_INFO_STANDARD) { |
ad7a2926b [CIFS] reduce che... |
477 |
FIND_FILE_STANDARD_INFO *pfData; |
5bafd7659 [CIFS] Add suppor... |
478 479 480 481 |
pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo; new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) + pfData->FileNameLength; |
8ad8aa353 cifs: prevent int... |
482 483 484 485 |
} else { u32 next_offset = le32_to_cpu(pDirInfo->NextEntryOffset); if (old_entry + next_offset < old_entry) { |
a0a3036b8 cifs: Standardize... |
486 487 |
cifs_dbg(VFS, "Invalid offset %u ", next_offset); |
8ad8aa353 cifs: prevent int... |
488 489 490 491 |
return NULL; } new_entry = old_entry + next_offset; } |
f96637be0 [CIFS] cifs: Rena... |
492 493 |
cifs_dbg(FYI, "new entry %p old entry %p ", new_entry, old_entry); |
1da177e4c Linux-2.6.12-rc2 |
494 |
/* validate that new_entry is not past end of SMB */ |
4523cc304 [CIFS] UID/GID ov... |
495 |
if (new_entry >= end_of_smb) { |
f96637be0 [CIFS] cifs: Rena... |
496 497 498 |
cifs_dbg(VFS, "search entry %p began after end of SMB %p old entry %p ", new_entry, end_of_smb, old_entry); |
1da177e4c Linux-2.6.12-rc2 |
499 |
return NULL; |
4523cc304 [CIFS] UID/GID ov... |
500 |
} else if (((level == SMB_FIND_FILE_INFO_STANDARD) && |
3870253ef [CIFS] more white... |
501 502 |
(new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) || ((level != SMB_FIND_FILE_INFO_STANDARD) && |
5bafd7659 [CIFS] Add suppor... |
503 |
(new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) { |
f96637be0 [CIFS] cifs: Rena... |
504 505 506 |
cifs_dbg(VFS, "search entry %p extends after end of SMB %p ", new_entry, end_of_smb); |
09d1db5c6 [PATCH] cifs: imp... |
507 |
return NULL; |
3870253ef [CIFS] more white... |
508 |
} else |
1da177e4c Linux-2.6.12-rc2 |
509 510 511 |
return new_entry; } |
cda0ec6a8 cifs: introduce c... |
512 513 514 515 516 517 |
struct cifs_dirent { const char *name; size_t namelen; u32 resume_key; u64 ino; }; |
3d519bd12 cifs: plumb smb2 ... |
518 519 520 521 522 523 524 |
static void cifs_fill_dirent_posix(struct cifs_dirent *de, const struct smb2_posix_info *info) { struct smb2_posix_info_parsed parsed; /* payload should have already been checked at this point */ if (posix_info_parse(info, NULL, &parsed) < 0) { |
a0a3036b8 cifs: Standardize... |
525 526 |
cifs_dbg(VFS, "Invalid POSIX info payload "); |
3d519bd12 cifs: plumb smb2 ... |
527 528 529 530 531 532 533 534 |
return; } de->name = parsed.name; de->namelen = parsed.name_len; de->resume_key = info->Ignored; de->ino = le64_to_cpu(info->Inode); } |
cda0ec6a8 cifs: introduce c... |
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 |
static void cifs_fill_dirent_unix(struct cifs_dirent *de, const FILE_UNIX_INFO *info, bool is_unicode) { de->name = &info->FileName[0]; if (is_unicode) de->namelen = cifs_unicode_bytelen(de->name); else de->namelen = strnlen(de->name, PATH_MAX); de->resume_key = info->ResumeKey; de->ino = le64_to_cpu(info->basic.UniqueId); } static void cifs_fill_dirent_dir(struct cifs_dirent *de, const FILE_DIRECTORY_INFO *info) { de->name = &info->FileName[0]; de->namelen = le32_to_cpu(info->FileNameLength); de->resume_key = info->FileIndex; } static void cifs_fill_dirent_full(struct cifs_dirent *de, const FILE_FULL_DIRECTORY_INFO *info) { de->name = &info->FileName[0]; de->namelen = le32_to_cpu(info->FileNameLength); de->resume_key = info->FileIndex; } static void cifs_fill_dirent_search(struct cifs_dirent *de, const SEARCH_ID_FULL_DIR_INFO *info) { de->name = &info->FileName[0]; de->namelen = le32_to_cpu(info->FileNameLength); de->resume_key = info->FileIndex; de->ino = le64_to_cpu(info->UniqueId); } static void cifs_fill_dirent_both(struct cifs_dirent *de, const FILE_BOTH_DIRECTORY_INFO *info) { de->name = &info->FileName[0]; de->namelen = le32_to_cpu(info->FileNameLength); de->resume_key = info->FileIndex; } static void cifs_fill_dirent_std(struct cifs_dirent *de, const FIND_FILE_STANDARD_INFO *info) { de->name = &info->FileName[0]; /* one byte length, no endianess conversion */ de->namelen = info->FileNameLength; de->resume_key = info->ResumeKey; } static int cifs_fill_dirent(struct cifs_dirent *de, const void *info, u16 level, bool is_unicode) { memset(de, 0, sizeof(*de)); switch (level) { |
3d519bd12 cifs: plumb smb2 ... |
595 596 597 |
case SMB_FIND_FILE_POSIX_INFO: cifs_fill_dirent_posix(de, info); break; |
cda0ec6a8 cifs: introduce c... |
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 |
case SMB_FIND_FILE_UNIX: cifs_fill_dirent_unix(de, info, is_unicode); break; case SMB_FIND_FILE_DIRECTORY_INFO: cifs_fill_dirent_dir(de, info); break; case SMB_FIND_FILE_FULL_DIRECTORY_INFO: cifs_fill_dirent_full(de, info); break; case SMB_FIND_FILE_ID_FULL_DIR_INFO: cifs_fill_dirent_search(de, info); break; case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: cifs_fill_dirent_both(de, info); break; case SMB_FIND_FILE_INFO_STANDARD: cifs_fill_dirent_std(de, info); break; default: |
f96637be0 [CIFS] cifs: Rena... |
617 618 |
cifs_dbg(FYI, "Unknown findfirst level %d ", level); |
cda0ec6a8 cifs: introduce c... |
619 620 621 622 623 |
return -EINVAL; } return 0; } |
1da177e4c Linux-2.6.12-rc2 |
624 625 626 |
#define UNICODE_DOT cpu_to_le16(0x2e) /* return 0 if no match and 1 for . (current directory) and 2 for .. (parent) */ |
cda0ec6a8 cifs: introduce c... |
627 |
static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode) |
1da177e4c Linux-2.6.12-rc2 |
628 629 |
{ int rc = 0; |
1da177e4c Linux-2.6.12-rc2 |
630 |
|
cda0ec6a8 cifs: introduce c... |
631 632 |
if (!de->name) return 0; |
1da177e4c Linux-2.6.12-rc2 |
633 |
|
cda0ec6a8 cifs: introduce c... |
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 |
if (is_unicode) { __le16 *ufilename = (__le16 *)de->name; if (de->namelen == 2) { /* check for . */ if (ufilename[0] == UNICODE_DOT) rc = 1; } else if (de->namelen == 4) { /* check for .. */ if (ufilename[0] == UNICODE_DOT && ufilename[1] == UNICODE_DOT) rc = 2; } } else /* ASCII */ { if (de->namelen == 1) { if (de->name[0] == '.') rc = 1; } else if (de->namelen == 2) { if (de->name[0] == '.' && de->name[1] == '.') rc = 2; |
1da177e4c Linux-2.6.12-rc2 |
653 654 655 656 657 |
} } return rc; } |
eafe87012 [CIFS] Fix readdi... |
658 659 |
/* Check if directory that we are searching has changed so we can decide whether we can use the cached search results from the previous search */ |
3870253ef [CIFS] more white... |
660 |
static int is_dir_changed(struct file *file) |
eafe87012 [CIFS] Fix readdi... |
661 |
{ |
496ad9aa8 new helper: file_... |
662 |
struct inode *inode = file_inode(file); |
c33f8d327 [CIFS] Remove unn... |
663 |
struct cifsInodeInfo *cifsInfo = CIFS_I(inode); |
eafe87012 [CIFS] Fix readdi... |
664 |
|
c33f8d327 [CIFS] Remove unn... |
665 |
if (cifsInfo->time == 0) |
eafe87012 [CIFS] Fix readdi... |
666 667 668 669 670 |
return 1; /* directory was changed, perhaps due to unlink */ else return 0; } |
0752f1522 [CIFS] make sure ... |
671 |
static int cifs_save_resume_key(const char *current_entry, |
eaf35b1ea cifs: use cifs_di... |
672 |
struct cifsFileInfo *file_info) |
0752f1522 [CIFS] make sure ... |
673 |
{ |
eaf35b1ea cifs: use cifs_di... |
674 675 |
struct cifs_dirent de; int rc; |
0752f1522 [CIFS] make sure ... |
676 |
|
eaf35b1ea cifs: use cifs_di... |
677 678 679 680 681 682 |
rc = cifs_fill_dirent(&de, current_entry, file_info->srch_inf.info_level, file_info->srch_inf.unicode); if (!rc) { file_info->srch_inf.presume_name = de.name; file_info->srch_inf.resume_name_len = de.namelen; file_info->srch_inf.resume_key = de.resume_key; |
0752f1522 [CIFS] make sure ... |
683 |
} |
0752f1522 [CIFS] make sure ... |
684 685 |
return rc; } |
92fc65a74 CIFS: Move readdi... |
686 687 688 689 690 691 692 693 |
/* * Find the corresponding entry in the search. Note that the SMB server returns * search entries for . and .. which complicates logic here if we choose to * parse for them and we do not assume that they are located in the findfirst * return buffer. We start counting in the buffer with entry 2 and increment for * every entry (do not increment for . or .. entry). */ static int |
be4ccdcc2 [readdir] convert... |
694 |
find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, |
d1542cf61 cifs: compute ful... |
695 696 |
struct file *file, char *full_path, char **current_entry, int *num_to_ret) |
1da177e4c Linux-2.6.12-rc2 |
697 |
{ |
2608bee74 cifs: Include bac... |
698 |
__u16 search_flags; |
1da177e4c Linux-2.6.12-rc2 |
699 700 701 |
int rc = 0; int pos_in_buf = 0; loff_t first_entry_in_buffer; |
be4ccdcc2 [readdir] convert... |
702 |
loff_t index_to_find = pos; |
92fc65a74 CIFS: Move readdi... |
703 |
struct cifsFileInfo *cfile = file->private_data; |
7119e220a cifs: get rid of ... |
704 |
struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file); |
92fc65a74 CIFS: Move readdi... |
705 |
struct TCP_Server_Info *server = tcon->ses->server; |
1da177e4c Linux-2.6.12-rc2 |
706 |
/* check if index in the buffer */ |
50c2f7538 [CIFS] whitespace... |
707 |
|
92fc65a74 CIFS: Move readdi... |
708 709 710 711 |
if (!server->ops->query_dir_first || !server->ops->query_dir_next) return -ENOSYS; if ((cfile == NULL) || (current_entry == NULL) || (num_to_ret == NULL)) |
1da177e4c Linux-2.6.12-rc2 |
712 |
return -ENOENT; |
50c2f7538 [CIFS] whitespace... |
713 |
|
92fc65a74 CIFS: Move readdi... |
714 715 716 |
*current_entry = NULL; first_entry_in_buffer = cfile->srch_inf.index_of_last_entry - cfile->srch_inf.entries_in_buffer; |
60808233f [CIFS] Readdir fi... |
717 |
|
92fc65a74 CIFS: Move readdi... |
718 719 720 721 722 723 724 |
/* * If first entry in buf is zero then is first buffer * in search response data which means it is likely . and .. * will be in this buffer, although some servers do not return * . and .. for the root of a drive and for those we need * to start two entries earlier. */ |
60808233f [CIFS] Readdir fi... |
725 |
|
3979877e5 [CIFS] Support fo... |
726 |
dump_cifs_file_struct(file, "In fce "); |
92fc65a74 CIFS: Move readdi... |
727 728 |
if (((index_to_find < cfile->srch_inf.index_of_last_entry) && is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) { |
1da177e4c Linux-2.6.12-rc2 |
729 |
/* close and restart search */ |
f96637be0 [CIFS] cifs: Rena... |
730 731 |
cifs_dbg(FYI, "search backing up - close and restart search "); |
3afca265b Clarify locking o... |
732 |
spin_lock(&cfile->file_info_lock); |
52755808d CIFS: Fix SMB2 re... |
733 |
if (server->ops->dir_needs_close(cfile)) { |
92fc65a74 CIFS: Move readdi... |
734 |
cfile->invalidHandle = true; |
3afca265b Clarify locking o... |
735 |
spin_unlock(&cfile->file_info_lock); |
f736906a7 CIFS: Fix wrong r... |
736 737 |
if (server->ops->close_dir) server->ops->close_dir(xid, tcon, &cfile->fid); |
ddb4cbfc5 [CIFS] Do not att... |
738 |
} else |
3afca265b Clarify locking o... |
739 |
spin_unlock(&cfile->file_info_lock); |
92fc65a74 CIFS: Move readdi... |
740 |
if (cfile->srch_inf.ntwrk_buf_start) { |
f96637be0 [CIFS] cifs: Rena... |
741 742 |
cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind "); |
92fc65a74 CIFS: Move readdi... |
743 744 |
if (cfile->srch_inf.smallBuf) cifs_small_buf_release(cfile->srch_inf. |
d47d7c1a8 [CIFS] CIFS readd... |
745 746 |
ntwrk_buf_start); else |
92fc65a74 CIFS: Move readdi... |
747 |
cifs_buf_release(cfile->srch_inf. |
d47d7c1a8 [CIFS] CIFS readd... |
748 |
ntwrk_buf_start); |
92fc65a74 CIFS: Move readdi... |
749 |
cfile->srch_inf.ntwrk_buf_start = NULL; |
1da177e4c Linux-2.6.12-rc2 |
750 |
} |
d1542cf61 cifs: compute ful... |
751 |
rc = initiate_cifs_search(xid, file, full_path); |
4523cc304 [CIFS] UID/GID ov... |
752 |
if (rc) { |
f96637be0 [CIFS] cifs: Rena... |
753 754 |
cifs_dbg(FYI, "error %d reinitiating a search on rewind ", |
b6b38f704 [CIFS] Neaten cER... |
755 |
rc); |
1da177e4c Linux-2.6.12-rc2 |
756 757 |
return rc; } |
7023676f9 cifs: check for N... |
758 |
/* FindFirst/Next set last_entry to NULL on malformed reply */ |
92fc65a74 CIFS: Move readdi... |
759 760 |
if (cfile->srch_inf.last_entry) cifs_save_resume_key(cfile->srch_inf.last_entry, cfile); |
1da177e4c Linux-2.6.12-rc2 |
761 |
} |
2608bee74 cifs: Include bac... |
762 763 764 |
search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; if (backup_cred(cifs_sb)) search_flags |= CIFS_SEARCH_BACKUP_SEARCH; |
92fc65a74 CIFS: Move readdi... |
765 766 |
while ((index_to_find >= cfile->srch_inf.index_of_last_entry) && (rc == 0) && !cfile->srch_inf.endOfSearch) { |
f96637be0 [CIFS] cifs: Rena... |
767 768 |
cifs_dbg(FYI, "calling findnext2 "); |
92fc65a74 CIFS: Move readdi... |
769 770 771 |
rc = server->ops->query_dir_next(xid, tcon, &cfile->fid, search_flags, &cfile->srch_inf); |
7023676f9 cifs: check for N... |
772 |
/* FindFirst/Next set last_entry to NULL on malformed reply */ |
92fc65a74 CIFS: Move readdi... |
773 774 |
if (cfile->srch_inf.last_entry) cifs_save_resume_key(cfile->srch_inf.last_entry, cfile); |
4523cc304 [CIFS] UID/GID ov... |
775 |
if (rc) |
1da177e4c Linux-2.6.12-rc2 |
776 777 |
return -ENOENT; } |
92fc65a74 CIFS: Move readdi... |
778 |
if (index_to_find < cfile->srch_inf.index_of_last_entry) { |
1da177e4c Linux-2.6.12-rc2 |
779 780 781 |
/* we found the buffer that contains the entry */ /* scan and find it */ int i; |
92fc65a74 CIFS: Move readdi... |
782 |
char *cur_ent; |
59a63e479 cifs: check ntwrk... |
783 784 785 786 787 788 789 790 791 |
char *end_of_smb; if (cfile->srch_inf.ntwrk_buf_start == NULL) { cifs_dbg(VFS, "ntwrk_buf_start is NULL during readdir "); return -EIO; } end_of_smb = cfile->srch_inf.ntwrk_buf_start + |
92fc65a74 CIFS: Move readdi... |
792 |
server->ops->calc_smb_size( |
9ec672bd1 cifs: update calc... |
793 794 |
cfile->srch_inf.ntwrk_buf_start, server); |
92fc65a74 CIFS: Move readdi... |
795 796 797 798 |
cur_ent = cfile->srch_inf.srch_entries_start; first_entry_in_buffer = cfile->srch_inf.index_of_last_entry - cfile->srch_inf.entries_in_buffer; |
1da177e4c Linux-2.6.12-rc2 |
799 |
pos_in_buf = index_to_find - first_entry_in_buffer; |
f96637be0 [CIFS] cifs: Rena... |
800 801 |
cifs_dbg(FYI, "found entry - pos_in_buf %d ", pos_in_buf); |
5bafd7659 [CIFS] Add suppor... |
802 |
|
92fc65a74 CIFS: Move readdi... |
803 |
for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) { |
dfb7533b5 [CIFS] Add stats ... |
804 |
/* go entry by entry figuring out which is first */ |
92fc65a74 CIFS: Move readdi... |
805 806 |
cur_ent = nxt_dir_entry(cur_ent, end_of_smb, cfile->srch_inf.info_level); |
1da177e4c Linux-2.6.12-rc2 |
807 |
} |
92fc65a74 CIFS: Move readdi... |
808 |
if ((cur_ent == NULL) && (i < pos_in_buf)) { |
1da177e4c Linux-2.6.12-rc2 |
809 |
/* BB fixme - check if we should flag this error */ |
f96637be0 [CIFS] cifs: Rena... |
810 811 812 |
cifs_dbg(VFS, "reached end of buf searching for pos in buf %d index to find %lld rc %d ", pos_in_buf, index_to_find, rc); |
1da177e4c Linux-2.6.12-rc2 |
813 814 |
} rc = 0; |
92fc65a74 CIFS: Move readdi... |
815 |
*current_entry = cur_ent; |
1da177e4c Linux-2.6.12-rc2 |
816 |
} else { |
f96637be0 [CIFS] cifs: Rena... |
817 818 |
cifs_dbg(FYI, "index not in buffer - could not findnext into it "); |
1da177e4c Linux-2.6.12-rc2 |
819 820 |
return 0; } |
92fc65a74 CIFS: Move readdi... |
821 |
if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) { |
f96637be0 [CIFS] cifs: Rena... |
822 823 |
cifs_dbg(FYI, "can not return entries pos_in_buf beyond last "); |
1da177e4c Linux-2.6.12-rc2 |
824 825 |
*num_to_ret = 0; } else |
92fc65a74 CIFS: Move readdi... |
826 |
*num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf; |
1da177e4c Linux-2.6.12-rc2 |
827 828 829 |
return rc; } |
be4ccdcc2 [readdir] convert... |
830 831 832 |
static int cifs_filldir(char *find_entry, struct file *file, struct dir_context *ctx, char *scratch_buf, unsigned int max_len) |
1da177e4c Linux-2.6.12-rc2 |
833 |
{ |
9feed6f8f cifs: cleanup cif... |
834 |
struct cifsFileInfo *file_info = file->private_data; |
7119e220a cifs: get rid of ... |
835 |
struct super_block *sb = file_inode(file)->i_sb; |
9feed6f8f cifs: cleanup cif... |
836 |
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
cda0ec6a8 cifs: introduce c... |
837 |
struct cifs_dirent de = { NULL, }; |
cc0bad755 cifs: add new cif... |
838 |
struct cifs_fattr fattr; |
9feed6f8f cifs: cleanup cif... |
839 |
struct qstr name; |
1da177e4c Linux-2.6.12-rc2 |
840 |
int rc = 0; |
9feed6f8f cifs: cleanup cif... |
841 |
ino_t ino; |
1da177e4c Linux-2.6.12-rc2 |
842 |
|
cda0ec6a8 cifs: introduce c... |
843 844 845 846 |
rc = cifs_fill_dirent(&de, find_entry, file_info->srch_inf.info_level, file_info->srch_inf.unicode); if (rc) return rc; |
5bafd7659 [CIFS] Add suppor... |
847 |
|
f16d59b41 cifs: use cifs_di... |
848 |
if (de.namelen > max_len) { |
f96637be0 [CIFS] cifs: Rena... |
849 850 851 |
cifs_dbg(VFS, "bad search response length %zd past smb end ", de.namelen); |
5bafd7659 [CIFS] Add suppor... |
852 853 |
return -EINVAL; } |
60808233f [CIFS] Readdir fi... |
854 |
/* skip . and .. since we added them first */ |
cda0ec6a8 cifs: introduce c... |
855 |
if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode)) |
60808233f [CIFS] Readdir fi... |
856 |
return 0; |
f16d59b41 cifs: use cifs_di... |
857 858 |
if (file_info->srch_inf.unicode) { struct nls_table *nlt = cifs_sb->local_nls; |
b693855fe Allow conversion ... |
859 |
int map_type; |
2baa26825 Remap reserved po... |
860 |
map_type = cifs_remap(cifs_sb); |
f16d59b41 cifs: use cifs_di... |
861 862 |
name.name = scratch_buf; name.len = |
acbbb76a2 CIFS: Rename *UCS... |
863 864 865 |
cifs_from_utf16((char *)name.name, (__le16 *)de.name, UNICODE_NAME_MAX, min_t(size_t, de.namelen, |
b693855fe Allow conversion ... |
866 |
(size_t)max_len), nlt, map_type); |
f16d59b41 cifs: use cifs_di... |
867 868 869 870 871 |
name.len -= nls_nullsize(nlt); } else { name.name = de.name; name.len = de.namelen; } |
1da177e4c Linux-2.6.12-rc2 |
872 |
|
9feed6f8f cifs: cleanup cif... |
873 |
switch (file_info->srch_inf.info_level) { |
3d519bd12 cifs: plumb smb2 ... |
874 875 876 877 878 |
case SMB_FIND_FILE_POSIX_INFO: cifs_posix_to_fattr(&fattr, (struct smb2_posix_info *)find_entry, cifs_sb); break; |
9feed6f8f cifs: cleanup cif... |
879 |
case SMB_FIND_FILE_UNIX: |
cc0bad755 cifs: add new cif... |
880 |
cifs_unix_basic_to_fattr(&fattr, |
9feed6f8f cifs: cleanup cif... |
881 882 883 884 885 886 887 888 |
&((FILE_UNIX_INFO *)find_entry)->basic, cifs_sb); break; case SMB_FIND_FILE_INFO_STANDARD: cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *)find_entry, cifs_sb); break; |
046aca3c2 cifs: Optimize re... |
889 890 891 892 893 |
case SMB_FIND_FILE_ID_FULL_DIR_INFO: cifs_fulldir_info_to_fattr(&fattr, (SEARCH_ID_FULL_DIR_INFO *)find_entry, cifs_sb); break; |
9feed6f8f cifs: cleanup cif... |
894 895 896 897 898 899 |
default: cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *)find_entry, cifs_sb); break; } |
b835bebe9 [CIFS] Fix CIFS r... |
900 |
|
f16d59b41 cifs: use cifs_di... |
901 902 |
if (de.ino && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { fattr.cf_uniqueid = de.ino; |
ec06aedd4 cifs: clean up ha... |
903 |
} else { |
0b8f18e35 cifs: convert cif... |
904 |
fattr.cf_uniqueid = iunique(sb, ROOT_I); |
ec06aedd4 cifs: clean up ha... |
905 906 |
cifs_autodisable_serverino(cifs_sb); } |
50c2f7538 [CIFS] whitespace... |
907 |
|
1b12b9c15 cifs: use Minshal... |
908 |
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && |
cb084b1a9 cifs: Rename MF s... |
909 |
couldbe_mf_symlink(&fattr)) |
1b12b9c15 cifs: use Minshal... |
910 911 912 913 914 915 |
/* * trying to get the type and mode can be slow, * so just call those regular files for now, and mark * for reval */ fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; |
1f1735cb7 cifs: Use file_de... |
916 |
cifs_prime_dcache(file_dentry(file), &name, &fattr); |
3870253ef [CIFS] more white... |
917 |
|
eb1b3fa5c cifs: rename cifs... |
918 |
ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); |
be4ccdcc2 [readdir] convert... |
919 |
return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype); |
1da177e4c Linux-2.6.12-rc2 |
920 |
} |
1da177e4c Linux-2.6.12-rc2 |
921 |
|
be4ccdcc2 [readdir] convert... |
922 |
int cifs_readdir(struct file *file, struct dir_context *ctx) |
1da177e4c Linux-2.6.12-rc2 |
923 924 |
{ int rc = 0; |
6d5786a34 CIFS: Rename Get/... |
925 926 |
unsigned int xid; int i; |
92fc65a74 CIFS: Move readdi... |
927 |
struct cifs_tcon *tcon; |
1da177e4c Linux-2.6.12-rc2 |
928 |
struct cifsFileInfo *cifsFile = NULL; |
3870253ef [CIFS] more white... |
929 |
char *current_entry; |
1da177e4c Linux-2.6.12-rc2 |
930 |
int num_to_fill = 0; |
3870253ef [CIFS] more white... |
931 |
char *tmp_buf = NULL; |
50c2f7538 [CIFS] whitespace... |
932 |
char *end_of_smb; |
18295796a cifs: fix length ... |
933 |
unsigned int max_len; |
d1542cf61 cifs: compute ful... |
934 |
char *full_path = NULL; |
1da177e4c Linux-2.6.12-rc2 |
935 |
|
6d5786a34 CIFS: Rename Get/... |
936 |
xid = get_xid(); |
1da177e4c Linux-2.6.12-rc2 |
937 |
|
d1542cf61 cifs: compute ful... |
938 939 940 941 942 |
full_path = build_path_from_dentry(file_dentry(file)); if (full_path == NULL) { rc = -ENOMEM; goto rddir2_exit; } |
6221ddd0f cifs: handle Find... |
943 944 945 946 947 |
/* * Ensure FindFirst doesn't fail before doing filldir() for '.' and * '..'. Otherwise we won't be able to notify VFS in case of failure. */ if (file->private_data == NULL) { |
d1542cf61 cifs: compute ful... |
948 |
rc = initiate_cifs_search(xid, file, full_path); |
f96637be0 [CIFS] cifs: Rena... |
949 950 |
cifs_dbg(FYI, "initiate cifs search rc %d ", rc); |
6221ddd0f cifs: handle Find... |
951 952 953 |
if (rc) goto rddir2_exit; } |
be4ccdcc2 [readdir] convert... |
954 955 |
if (!dir_emit_dots(file, ctx)) goto rddir2_exit; |
1da177e4c Linux-2.6.12-rc2 |
956 |
|
be4ccdcc2 [readdir] convert... |
957 958 959 960 |
/* 1) If search is active, is in current search buffer? if it before then restart search if after then keep searching till find it */ |
be4ccdcc2 [readdir] convert... |
961 962 963 964 965 966 |
cifsFile = file->private_data; if (cifsFile->srch_inf.endOfSearch) { if (cifsFile->srch_inf.emptyDir) { cifs_dbg(FYI, "End of search, empty dir "); rc = 0; |
1da177e4c Linux-2.6.12-rc2 |
967 968 |
goto rddir2_exit; } |
be4ccdcc2 [readdir] convert... |
969 970 971 972 973 974 |
} /* else { cifsFile->invalidHandle = true; tcon->ses->server->close(xid, tcon, &cifsFile->fid); } */ tcon = tlink_tcon(cifsFile->tlink); |
d1542cf61 cifs: compute ful... |
975 976 |
rc = find_cifs_entry(xid, tcon, ctx->pos, file, full_path, ¤t_entry, &num_to_fill); |
be4ccdcc2 [readdir] convert... |
977 978 979 980 981 982 983 984 |
if (rc) { cifs_dbg(FYI, "fce error %d ", rc); goto rddir2_exit; } else if (current_entry != NULL) { cifs_dbg(FYI, "entry %lld found ", ctx->pos); } else { |
a0a3036b8 cifs: Standardize... |
985 986 |
cifs_dbg(FYI, "Could not find entry "); |
be4ccdcc2 [readdir] convert... |
987 988 989 990 991 992 |
goto rddir2_exit; } cifs_dbg(FYI, "loop through %d times filling dir for net buf %p ", num_to_fill, cifsFile->srch_inf.ntwrk_buf_start); max_len = tcon->ses->server->ops->calc_smb_size( |
9ec672bd1 cifs: update calc... |
993 994 |
cifsFile->srch_inf.ntwrk_buf_start, tcon->ses->server); |
be4ccdcc2 [readdir] convert... |
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 |
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL); if (tmp_buf == NULL) { rc = -ENOMEM; goto rddir2_exit; } for (i = 0; i < num_to_fill; i++) { if (current_entry == NULL) { /* evaluate whether this case is an error */ cifs_dbg(VFS, "past SMB end, num to fill %d i %d ", num_to_fill, i); |
f55fdcca6 fs: cifs: check k... |
1009 1010 |
break; } |
be4ccdcc2 [readdir] convert... |
1011 1012 1013 1014 |
/* * if buggy server returns . and .. late do we want to * check for that here? */ |
01b9b0b28 cifs_dbg() output... |
1015 |
*tmp_buf = 0; |
be4ccdcc2 [readdir] convert... |
1016 1017 1018 1019 |
rc = cifs_filldir(current_entry, file, ctx, tmp_buf, max_len); if (rc) { if (rc > 0) |
7ca85ba75 [CIFS] Fix readdi... |
1020 |
rc = 0; |
be4ccdcc2 [readdir] convert... |
1021 |
break; |
1da177e4c Linux-2.6.12-rc2 |
1022 |
} |
be4ccdcc2 [readdir] convert... |
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 |
ctx->pos++; if (ctx->pos == cifsFile->srch_inf.index_of_last_entry) { cifs_dbg(FYI, "last entry in buf at pos %lld %s ", ctx->pos, tmp_buf); cifs_save_resume_key(current_entry, cifsFile); break; } else current_entry = nxt_dir_entry(current_entry, end_of_smb, cifsFile->srch_inf.info_level); } kfree(tmp_buf); |
1da177e4c Linux-2.6.12-rc2 |
1038 1039 |
rddir2_exit: |
d1542cf61 cifs: compute ful... |
1040 |
kfree(full_path); |
6d5786a34 CIFS: Rename Get/... |
1041 |
free_xid(xid); |
1da177e4c Linux-2.6.12-rc2 |
1042 1043 |
return rc; } |