diff options
author | Jeff Layton <jlayton@redhat.com> | 2009-07-09 01:46:37 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2009-07-09 19:05:48 -0400 |
commit | 0b8f18e358384a52c1ed7fa7129c08e7eaf86bb6 (patch) | |
tree | ba5292a38d8910c6b3a3303a3c7f88491e1708af /fs/cifs | |
parent | b77863bfa153e886f9f8faf1a791ba57a36efed0 (diff) |
cifs: convert cifs_get_inode_info and non-posix readdir to use cifs_iget
cifs: convert cifs_get_inode_info and non-posix readdir to use cifs_iget
Rather than allocating an inode and filling it out, have
cifs_get_inode_info fill out a cifs_fattr and call cifs_iget. This means
a pretty hefty reorganization of cifs_get_inode_info.
For the readdir codepath, add a couple of new functions for filling out
cifs_fattr's from different FindFile response infolevels.
Finally, remove cifs_new_inode since there are no more callers.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/cifsacl.c | 26 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 6 | ||||
-rw-r--r-- | fs/cifs/inode.c | 397 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 350 |
5 files changed, 252 insertions, 529 deletions
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 1403b5d86a73..6941c22398a6 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -327,7 +327,7 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl) | |||
327 | 327 | ||
328 | static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | 328 | static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, |
329 | struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, | 329 | struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, |
330 | struct inode *inode) | 330 | struct cifs_fattr *fattr) |
331 | { | 331 | { |
332 | int i; | 332 | int i; |
333 | int num_aces = 0; | 333 | int num_aces = 0; |
@@ -340,7 +340,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
340 | if (!pdacl) { | 340 | if (!pdacl) { |
341 | /* no DACL in the security descriptor, set | 341 | /* no DACL in the security descriptor, set |
342 | all the permissions for user/group/other */ | 342 | all the permissions for user/group/other */ |
343 | inode->i_mode |= S_IRWXUGO; | 343 | fattr->cf_mode |= S_IRWXUGO; |
344 | return; | 344 | return; |
345 | } | 345 | } |
346 | 346 | ||
@@ -357,7 +357,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
357 | /* reset rwx permissions for user/group/other. | 357 | /* reset rwx permissions for user/group/other. |
358 | Also, if num_aces is 0 i.e. DACL has no ACEs, | 358 | Also, if num_aces is 0 i.e. DACL has no ACEs, |
359 | user/group/other have no permissions */ | 359 | user/group/other have no permissions */ |
360 | inode->i_mode &= ~(S_IRWXUGO); | 360 | fattr->cf_mode &= ~(S_IRWXUGO); |
361 | 361 | ||
362 | acl_base = (char *)pdacl; | 362 | acl_base = (char *)pdacl; |
363 | acl_size = sizeof(struct cifs_acl); | 363 | acl_size = sizeof(struct cifs_acl); |
@@ -379,17 +379,17 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
379 | if (compare_sids(&(ppace[i]->sid), pownersid)) | 379 | if (compare_sids(&(ppace[i]->sid), pownersid)) |
380 | access_flags_to_mode(ppace[i]->access_req, | 380 | access_flags_to_mode(ppace[i]->access_req, |
381 | ppace[i]->type, | 381 | ppace[i]->type, |
382 | &(inode->i_mode), | 382 | &fattr->cf_mode, |
383 | &user_mask); | 383 | &user_mask); |
384 | if (compare_sids(&(ppace[i]->sid), pgrpsid)) | 384 | if (compare_sids(&(ppace[i]->sid), pgrpsid)) |
385 | access_flags_to_mode(ppace[i]->access_req, | 385 | access_flags_to_mode(ppace[i]->access_req, |
386 | ppace[i]->type, | 386 | ppace[i]->type, |
387 | &(inode->i_mode), | 387 | &fattr->cf_mode, |
388 | &group_mask); | 388 | &group_mask); |
389 | if (compare_sids(&(ppace[i]->sid), &sid_everyone)) | 389 | if (compare_sids(&(ppace[i]->sid), &sid_everyone)) |
390 | access_flags_to_mode(ppace[i]->access_req, | 390 | access_flags_to_mode(ppace[i]->access_req, |
391 | ppace[i]->type, | 391 | ppace[i]->type, |
392 | &(inode->i_mode), | 392 | &fattr->cf_mode, |
393 | &other_mask); | 393 | &other_mask); |
394 | 394 | ||
395 | /* memcpy((void *)(&(cifscred->aces[i])), | 395 | /* memcpy((void *)(&(cifscred->aces[i])), |
@@ -464,7 +464,7 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) | |||
464 | 464 | ||
465 | /* Convert CIFS ACL to POSIX form */ | 465 | /* Convert CIFS ACL to POSIX form */ |
466 | static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | 466 | static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, |
467 | struct inode *inode) | 467 | struct cifs_fattr *fattr) |
468 | { | 468 | { |
469 | int rc; | 469 | int rc; |
470 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; | 470 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; |
@@ -472,7 +472,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
472 | char *end_of_acl = ((char *)pntsd) + acl_len; | 472 | char *end_of_acl = ((char *)pntsd) + acl_len; |
473 | __u32 dacloffset; | 473 | __u32 dacloffset; |
474 | 474 | ||
475 | if ((inode == NULL) || (pntsd == NULL)) | 475 | if (pntsd == NULL) |
476 | return -EIO; | 476 | return -EIO; |
477 | 477 | ||
478 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + | 478 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + |
@@ -497,7 +497,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
497 | 497 | ||
498 | if (dacloffset) | 498 | if (dacloffset) |
499 | parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, | 499 | parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, |
500 | group_sid_ptr, inode); | 500 | group_sid_ptr, fattr); |
501 | else | 501 | else |
502 | cFYI(1, ("no ACL")); /* BB grant all or default perms? */ | 502 | cFYI(1, ("no ACL")); /* BB grant all or default perms? */ |
503 | 503 | ||
@@ -508,7 +508,6 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
508 | memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, | 508 | memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, |
509 | sizeof(struct cifs_sid)); */ | 509 | sizeof(struct cifs_sid)); */ |
510 | 510 | ||
511 | |||
512 | return 0; | 511 | return 0; |
513 | } | 512 | } |
514 | 513 | ||
@@ -671,8 +670,9 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
671 | } | 670 | } |
672 | 671 | ||
673 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ | 672 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ |
674 | void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode, | 673 | void |
675 | const char *path, const __u16 *pfid) | 674 | cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, |
675 | struct inode *inode, const char *path, const __u16 *pfid) | ||
676 | { | 676 | { |
677 | struct cifs_ntsd *pntsd = NULL; | 677 | struct cifs_ntsd *pntsd = NULL; |
678 | u32 acllen = 0; | 678 | u32 acllen = 0; |
@@ -687,7 +687,7 @@ void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode, | |||
687 | 687 | ||
688 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ | 688 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ |
689 | if (pntsd) | 689 | if (pntsd) |
690 | rc = parse_sec_desc(pntsd, acllen, inode); | 690 | rc = parse_sec_desc(pntsd, acllen, fattr); |
691 | if (rc) | 691 | if (rc) |
692 | cFYI(1, ("parse sec desc failed rc = %d", rc)); | 692 | cFYI(1, ("parse sec desc failed rc = %d", rc)); |
693 | 693 | ||
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index e6435cba8113..8bcf5a4bcded 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -479,6 +479,8 @@ struct dfs_info3_param { | |||
479 | */ | 479 | */ |
480 | 480 | ||
481 | #define CIFS_FATTR_DFS_REFERRAL 0x1 | 481 | #define CIFS_FATTR_DFS_REFERRAL 0x1 |
482 | #define CIFS_FATTR_DELETE_PENDING 0x2 | ||
483 | #define CIFS_FATTR_NEED_REVAL 0x4 | ||
482 | 484 | ||
483 | struct cifs_fattr { | 485 | struct cifs_fattr { |
484 | u32 cf_flags; | 486 | u32 cf_flags; |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 37c11c08c529..da8fbf565991 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -102,7 +102,6 @@ extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, | |||
102 | FILE_UNIX_BASIC_INFO *info, | 102 | FILE_UNIX_BASIC_INFO *info, |
103 | struct cifs_sb_info *cifs_sb); | 103 | struct cifs_sb_info *cifs_sb); |
104 | extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr); | 104 | extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr); |
105 | extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum); | ||
106 | extern struct inode *cifs_iget(struct super_block *sb, | 105 | extern struct inode *cifs_iget(struct super_block *sb, |
107 | struct cifs_fattr *fattr); | 106 | struct cifs_fattr *fattr); |
108 | 107 | ||
@@ -113,8 +112,9 @@ extern int cifs_get_inode_info(struct inode **pinode, | |||
113 | extern int cifs_get_inode_info_unix(struct inode **pinode, | 112 | extern int cifs_get_inode_info_unix(struct inode **pinode, |
114 | const unsigned char *search_path, | 113 | const unsigned char *search_path, |
115 | struct super_block *sb, int xid); | 114 | struct super_block *sb, int xid); |
116 | extern void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode, | 115 | extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, |
117 | const char *path, const __u16 *pfid); | 116 | struct cifs_fattr *fattr, struct inode *inode, |
117 | const char *path, const __u16 *pfid); | ||
118 | extern int mode_to_acl(struct inode *inode, const char *path, __u64); | 118 | extern int mode_to_acl(struct inode *inode, const char *path, __u64); |
119 | 119 | ||
120 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, | 120 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 55b616bb381e..a807397f444e 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -82,23 +82,34 @@ void | |||
82 | cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) | 82 | cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) |
83 | { | 83 | { |
84 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); | 84 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); |
85 | unsigned long now = jiffies; | 85 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
86 | unsigned long oldtime = cifs_i->time; | ||
86 | 87 | ||
87 | inode->i_atime = fattr->cf_atime; | 88 | inode->i_atime = fattr->cf_atime; |
88 | inode->i_mtime = fattr->cf_mtime; | 89 | inode->i_mtime = fattr->cf_mtime; |
89 | inode->i_ctime = fattr->cf_ctime; | 90 | inode->i_ctime = fattr->cf_ctime; |
90 | inode->i_mode = fattr->cf_mode; | ||
91 | inode->i_rdev = fattr->cf_rdev; | 91 | inode->i_rdev = fattr->cf_rdev; |
92 | inode->i_nlink = fattr->cf_nlink; | 92 | inode->i_nlink = fattr->cf_nlink; |
93 | inode->i_uid = fattr->cf_uid; | 93 | inode->i_uid = fattr->cf_uid; |
94 | inode->i_gid = fattr->cf_gid; | 94 | inode->i_gid = fattr->cf_gid; |
95 | 95 | ||
96 | /* if dynperm is set, don't clobber existing mode */ | ||
97 | if (inode->i_state & I_NEW || | ||
98 | !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) | ||
99 | inode->i_mode = fattr->cf_mode; | ||
100 | |||
96 | cifs_i->cifsAttrs = fattr->cf_cifsattrs; | 101 | cifs_i->cifsAttrs = fattr->cf_cifsattrs; |
97 | cifs_i->uniqueid = fattr->cf_uniqueid; | 102 | cifs_i->uniqueid = fattr->cf_uniqueid; |
98 | 103 | ||
104 | if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL) | ||
105 | cifs_i->time = 0; | ||
106 | else | ||
107 | cifs_i->time = jiffies; | ||
108 | |||
99 | cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode, | 109 | cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode, |
100 | cifs_i->time, now)); | 110 | oldtime, cifs_i->time)); |
101 | cifs_i->time = now; | 111 | |
112 | cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING; | ||
102 | 113 | ||
103 | /* | 114 | /* |
104 | * Can't safely change the file size here if the client is writing to | 115 | * Can't safely change the file size here if the client is writing to |
@@ -219,49 +230,6 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) | |||
219 | fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; | 230 | fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; |
220 | } | 231 | } |
221 | 232 | ||
222 | /** | ||
223 | * cifs_new inode - create new inode, initialize, and hash it | ||
224 | * @sb - pointer to superblock | ||
225 | * @inum - if valid pointer and serverino is enabled, replace i_ino with val | ||
226 | * | ||
227 | * Create a new inode, initialize it for CIFS and hash it. Returns the new | ||
228 | * inode or NULL if one couldn't be allocated. | ||
229 | * | ||
230 | * If the share isn't mounted with "serverino" or inum is a NULL pointer then | ||
231 | * we'll just use the inode number assigned by new_inode(). Note that this can | ||
232 | * mean i_ino collisions since the i_ino assigned by new_inode is not | ||
233 | * guaranteed to be unique. | ||
234 | */ | ||
235 | struct inode * | ||
236 | cifs_new_inode(struct super_block *sb, __u64 *inum) | ||
237 | { | ||
238 | struct inode *inode; | ||
239 | |||
240 | inode = new_inode(sb); | ||
241 | if (inode == NULL) | ||
242 | return NULL; | ||
243 | |||
244 | /* | ||
245 | * BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we | ||
246 | * stop passing inum as ptr. Are there sanity checks we can use to | ||
247 | * ensure that the server is really filling in that field? Also, | ||
248 | * if serverino is disabled, perhaps we should be using iunique()? | ||
249 | */ | ||
250 | if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) | ||
251 | inode->i_ino = (unsigned long) *inum; | ||
252 | |||
253 | /* | ||
254 | * must set this here instead of cifs_alloc_inode since VFS will | ||
255 | * clobber i_flags | ||
256 | */ | ||
257 | if (sb->s_flags & MS_NOATIME) | ||
258 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | ||
259 | |||
260 | insert_inode_hash(inode); | ||
261 | |||
262 | return inode; | ||
263 | } | ||
264 | |||
265 | int cifs_get_inode_info_unix(struct inode **pinode, | 233 | int cifs_get_inode_info_unix(struct inode **pinode, |
266 | const unsigned char *full_path, | 234 | const unsigned char *full_path, |
267 | struct super_block *sb, int xid) | 235 | struct super_block *sb, int xid) |
@@ -302,9 +270,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
302 | return rc; | 270 | return rc; |
303 | } | 271 | } |
304 | 272 | ||
305 | static int decode_sfu_inode(struct inode *inode, __u64 size, | 273 | static int |
306 | const unsigned char *path, | 274 | cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, |
307 | struct cifs_sb_info *cifs_sb, int xid) | 275 | struct cifs_sb_info *cifs_sb, int xid) |
308 | { | 276 | { |
309 | int rc; | 277 | int rc; |
310 | int oplock = 0; | 278 | int oplock = 0; |
@@ -316,10 +284,15 @@ static int decode_sfu_inode(struct inode *inode, __u64 size, | |||
316 | 284 | ||
317 | pbuf = buf; | 285 | pbuf = buf; |
318 | 286 | ||
319 | if (size == 0) { | 287 | fattr->cf_mode &= ~S_IFMT; |
320 | inode->i_mode |= S_IFIFO; | 288 | |
289 | if (fattr->cf_eof == 0) { | ||
290 | fattr->cf_mode |= S_IFIFO; | ||
291 | fattr->cf_dtype = DT_FIFO; | ||
321 | return 0; | 292 | return 0; |
322 | } else if (size < 8) { | 293 | } else if (fattr->cf_eof < 8) { |
294 | fattr->cf_mode |= S_IFREG; | ||
295 | fattr->cf_dtype = DT_REG; | ||
323 | return -EINVAL; /* EOPNOTSUPP? */ | 296 | return -EINVAL; /* EOPNOTSUPP? */ |
324 | } | 297 | } |
325 | 298 | ||
@@ -331,42 +304,46 @@ static int decode_sfu_inode(struct inode *inode, __u64 size, | |||
331 | if (rc == 0) { | 304 | if (rc == 0) { |
332 | int buf_type = CIFS_NO_BUFFER; | 305 | int buf_type = CIFS_NO_BUFFER; |
333 | /* Read header */ | 306 | /* Read header */ |
334 | rc = CIFSSMBRead(xid, pTcon, | 307 | rc = CIFSSMBRead(xid, pTcon, netfid, |
335 | netfid, | ||
336 | 24 /* length */, 0 /* offset */, | 308 | 24 /* length */, 0 /* offset */, |
337 | &bytes_read, &pbuf, &buf_type); | 309 | &bytes_read, &pbuf, &buf_type); |
338 | if ((rc == 0) && (bytes_read >= 8)) { | 310 | if ((rc == 0) && (bytes_read >= 8)) { |
339 | if (memcmp("IntxBLK", pbuf, 8) == 0) { | 311 | if (memcmp("IntxBLK", pbuf, 8) == 0) { |
340 | cFYI(1, ("Block device")); | 312 | cFYI(1, ("Block device")); |
341 | inode->i_mode |= S_IFBLK; | 313 | fattr->cf_mode |= S_IFBLK; |
314 | fattr->cf_dtype = DT_BLK; | ||
342 | if (bytes_read == 24) { | 315 | if (bytes_read == 24) { |
343 | /* we have enough to decode dev num */ | 316 | /* we have enough to decode dev num */ |
344 | __u64 mjr; /* major */ | 317 | __u64 mjr; /* major */ |
345 | __u64 mnr; /* minor */ | 318 | __u64 mnr; /* minor */ |
346 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); | 319 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); |
347 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); | 320 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); |
348 | inode->i_rdev = MKDEV(mjr, mnr); | 321 | fattr->cf_rdev = MKDEV(mjr, mnr); |
349 | } | 322 | } |
350 | } else if (memcmp("IntxCHR", pbuf, 8) == 0) { | 323 | } else if (memcmp("IntxCHR", pbuf, 8) == 0) { |
351 | cFYI(1, ("Char device")); | 324 | cFYI(1, ("Char device")); |
352 | inode->i_mode |= S_IFCHR; | 325 | fattr->cf_mode |= S_IFCHR; |
326 | fattr->cf_dtype = DT_CHR; | ||
353 | if (bytes_read == 24) { | 327 | if (bytes_read == 24) { |
354 | /* we have enough to decode dev num */ | 328 | /* we have enough to decode dev num */ |
355 | __u64 mjr; /* major */ | 329 | __u64 mjr; /* major */ |
356 | __u64 mnr; /* minor */ | 330 | __u64 mnr; /* minor */ |
357 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); | 331 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); |
358 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); | 332 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); |
359 | inode->i_rdev = MKDEV(mjr, mnr); | 333 | fattr->cf_rdev = MKDEV(mjr, mnr); |
360 | } | 334 | } |
361 | } else if (memcmp("IntxLNK", pbuf, 7) == 0) { | 335 | } else if (memcmp("IntxLNK", pbuf, 7) == 0) { |
362 | cFYI(1, ("Symlink")); | 336 | cFYI(1, ("Symlink")); |
363 | inode->i_mode |= S_IFLNK; | 337 | fattr->cf_mode |= S_IFLNK; |
338 | fattr->cf_dtype = DT_LNK; | ||
364 | } else { | 339 | } else { |
365 | inode->i_mode |= S_IFREG; /* file? */ | 340 | fattr->cf_mode |= S_IFREG; /* file? */ |
341 | fattr->cf_dtype = DT_REG; | ||
366 | rc = -EOPNOTSUPP; | 342 | rc = -EOPNOTSUPP; |
367 | } | 343 | } |
368 | } else { | 344 | } else { |
369 | inode->i_mode |= S_IFREG; /* then it is a file */ | 345 | fattr->cf_mode |= S_IFREG; /* then it is a file */ |
346 | fattr->cf_dtype = DT_REG; | ||
370 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ | 347 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ |
371 | } | 348 | } |
372 | CIFSSMBClose(xid, pTcon, netfid); | 349 | CIFSSMBClose(xid, pTcon, netfid); |
@@ -376,9 +353,13 @@ static int decode_sfu_inode(struct inode *inode, __u64 size, | |||
376 | 353 | ||
377 | #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ | 354 | #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ |
378 | 355 | ||
379 | static int get_sfu_mode(struct inode *inode, | 356 | /* |
380 | const unsigned char *path, | 357 | * Fetch mode bits as provided by SFU. |
381 | struct cifs_sb_info *cifs_sb, int xid) | 358 | * |
359 | * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ? | ||
360 | */ | ||
361 | static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, | ||
362 | struct cifs_sb_info *cifs_sb, int xid) | ||
382 | { | 363 | { |
383 | #ifdef CONFIG_CIFS_XATTR | 364 | #ifdef CONFIG_CIFS_XATTR |
384 | ssize_t rc; | 365 | ssize_t rc; |
@@ -386,68 +367,80 @@ static int get_sfu_mode(struct inode *inode, | |||
386 | __u32 mode; | 367 | __u32 mode; |
387 | 368 | ||
388 | rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", | 369 | rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", |
389 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, | 370 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, |
390 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 371 | cifs_sb->mnt_cifs_flags & |
372 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
391 | if (rc < 0) | 373 | if (rc < 0) |
392 | return (int)rc; | 374 | return (int)rc; |
393 | else if (rc > 3) { | 375 | else if (rc > 3) { |
394 | mode = le32_to_cpu(*((__le32 *)ea_value)); | 376 | mode = le32_to_cpu(*((__le32 *)ea_value)); |
395 | inode->i_mode &= ~SFBITS_MASK; | 377 | fattr->cf_mode &= ~SFBITS_MASK; |
396 | cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode)); | 378 | cFYI(1, ("special bits 0%o org mode 0%o", mode, |
397 | inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode; | 379 | fattr->cf_mode)); |
380 | fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode; | ||
398 | cFYI(1, ("special mode bits 0%o", mode)); | 381 | cFYI(1, ("special mode bits 0%o", mode)); |
399 | return 0; | ||
400 | } else { | ||
401 | return 0; | ||
402 | } | 382 | } |
383 | |||
384 | return 0; | ||
403 | #else | 385 | #else |
404 | return -EOPNOTSUPP; | 386 | return -EOPNOTSUPP; |
405 | #endif | 387 | #endif |
406 | } | 388 | } |
407 | 389 | ||
408 | /* | 390 | /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ |
409 | * Needed to setup inode data for the directory which is the | 391 | void |
410 | * junction to the new submount (ie to setup the fake directory | 392 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, |
411 | * which represents a DFS referral) | 393 | struct cifs_sb_info *cifs_sb, bool adjust_tz) |
412 | */ | ||
413 | static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat, | ||
414 | struct super_block *sb) | ||
415 | { | 394 | { |
416 | memset(pfnd_dat, 0, sizeof(FILE_ALL_INFO)); | 395 | memset(fattr, 0, sizeof(*fattr)); |
417 | 396 | fattr->cf_cifsattrs = le32_to_cpu(info->Attributes); | |
418 | /* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0); | 397 | if (info->DeletePending) |
419 | __le64 pfnd_dat->EndOfFile = cpu_to_le64(0); | 398 | fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING; |
420 | __u8 pfnd_dat->DeletePending = 0; | 399 | |
421 | __u8 pfnd_data->Directory = 0; | 400 | if (info->LastAccessTime) |
422 | __le32 pfnd_dat->EASize = 0; | 401 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
423 | __u64 pfnd_dat->IndexNumber = 0; | 402 | else |
424 | __u64 pfnd_dat->IndexNumber1 = 0; */ | 403 | fattr->cf_atime = CURRENT_TIME; |
425 | pfnd_dat->CreationTime = | 404 | |
426 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 405 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
427 | pfnd_dat->LastAccessTime = | 406 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
428 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 407 | |
429 | pfnd_dat->LastWriteTime = | 408 | if (adjust_tz) { |
430 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 409 | fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; |
431 | pfnd_dat->ChangeTime = | 410 | fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; |
432 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 411 | } |
433 | pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY); | 412 | |
434 | pfnd_dat->NumberOfLinks = cpu_to_le32(2); | 413 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
414 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | ||
415 | |||
416 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { | ||
417 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; | ||
418 | fattr->cf_dtype = DT_DIR; | ||
419 | } else { | ||
420 | fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; | ||
421 | fattr->cf_dtype = DT_REG; | ||
422 | } | ||
423 | |||
424 | /* clear write bits if ATTR_READONLY is set */ | ||
425 | if (fattr->cf_cifsattrs & ATTR_READONLY) | ||
426 | fattr->cf_mode &= ~(S_IWUGO); | ||
427 | |||
428 | fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); | ||
429 | |||
430 | fattr->cf_uid = cifs_sb->mnt_uid; | ||
431 | fattr->cf_gid = cifs_sb->mnt_gid; | ||
435 | } | 432 | } |
436 | 433 | ||
437 | int cifs_get_inode_info(struct inode **pinode, | 434 | int cifs_get_inode_info(struct inode **pinode, |
438 | const unsigned char *full_path, FILE_ALL_INFO *pfindData, | 435 | const unsigned char *full_path, FILE_ALL_INFO *pfindData, |
439 | struct super_block *sb, int xid, const __u16 *pfid) | 436 | struct super_block *sb, int xid, const __u16 *pfid) |
440 | { | 437 | { |
441 | int rc = 0; | 438 | int rc = 0, tmprc; |
442 | __u32 attr; | ||
443 | struct cifsInodeInfo *cifsInfo; | ||
444 | struct cifsTconInfo *pTcon; | 439 | struct cifsTconInfo *pTcon; |
445 | struct inode *inode; | ||
446 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 440 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
447 | char *buf = NULL; | 441 | char *buf = NULL; |
448 | bool adjustTZ = false; | 442 | bool adjustTZ = false; |
449 | bool is_dfs_referral = false; | 443 | struct cifs_fattr fattr; |
450 | umode_t default_mode; | ||
451 | 444 | ||
452 | pTcon = cifs_sb->tcon; | 445 | pTcon = cifs_sb->tcon; |
453 | cFYI(1, ("Getting info on %s", full_path)); | 446 | cFYI(1, ("Getting info on %s", full_path)); |
@@ -482,163 +475,82 @@ int cifs_get_inode_info(struct inode **pinode, | |||
482 | adjustTZ = true; | 475 | adjustTZ = true; |
483 | } | 476 | } |
484 | } | 477 | } |
485 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ | 478 | |
486 | if (rc == -EREMOTE) { | 479 | if (!rc) { |
487 | is_dfs_referral = true; | 480 | cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData, |
488 | fill_fake_finddata(pfindData, sb); | 481 | cifs_sb, adjustTZ); |
482 | } else if (rc == -EREMOTE) { | ||
483 | cifs_create_dfs_fattr(&fattr, sb); | ||
489 | rc = 0; | 484 | rc = 0; |
490 | } else if (rc) | 485 | } else { |
491 | goto cgii_exit; | 486 | goto cgii_exit; |
487 | } | ||
492 | 488 | ||
493 | attr = le32_to_cpu(pfindData->Attributes); | 489 | /* |
494 | 490 | * If an inode wasn't passed in, then get the inode number | |
495 | /* get new inode */ | 491 | * |
492 | * Is an i_ino of zero legal? Can we use that to check if the server | ||
493 | * supports returning inode numbers? Are there other sanity checks we | ||
494 | * can use to ensure that the server is really filling in that field? | ||
495 | * | ||
496 | * We can not use the IndexNumber field by default from Windows or | ||
497 | * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA | ||
498 | * CIFS spec claims that this value is unique within the scope of a | ||
499 | * share, and the windows docs hint that it's actually unique | ||
500 | * per-machine. | ||
501 | * | ||
502 | * There may be higher info levels that work but are there Windows | ||
503 | * server or network appliances for which IndexNumber field is not | ||
504 | * guaranteed unique? | ||
505 | */ | ||
496 | if (*pinode == NULL) { | 506 | if (*pinode == NULL) { |
497 | __u64 inode_num; | ||
498 | __u64 *pinum = &inode_num; | ||
499 | |||
500 | /* Is an i_ino of zero legal? Can we use that to check | ||
501 | if the server supports returning inode numbers? Are | ||
502 | there other sanity checks we can use to ensure that | ||
503 | the server is really filling in that field? */ | ||
504 | |||
505 | /* We can not use the IndexNumber field by default from | ||
506 | Windows or Samba (in ALL_INFO buf) but we can request | ||
507 | it explicitly. It may not be unique presumably if | ||
508 | the server has multiple devices mounted under one share */ | ||
509 | |||
510 | /* There may be higher info levels that work but are | ||
511 | there Windows server or network appliances for which | ||
512 | IndexNumber field is not guaranteed unique? */ | ||
513 | |||
514 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | 507 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { |
515 | int rc1 = 0; | 508 | int rc1 = 0; |
516 | 509 | ||
517 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, | 510 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, |
518 | full_path, pinum, | 511 | full_path, &fattr.cf_uniqueid, |
519 | cifs_sb->local_nls, | 512 | cifs_sb->local_nls, |
520 | cifs_sb->mnt_cifs_flags & | 513 | cifs_sb->mnt_cifs_flags & |
521 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 514 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
522 | if (rc1) { | 515 | if (rc1) { |
523 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); | ||
524 | pinum = NULL; | ||
525 | /* BB EOPNOSUPP disable SERVER_INUM? */ | 516 | /* BB EOPNOSUPP disable SERVER_INUM? */ |
517 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); | ||
518 | fattr.cf_uniqueid = iunique(sb, ROOT_I); | ||
526 | } | 519 | } |
527 | } else { | 520 | } else { |
528 | pinum = NULL; | 521 | fattr.cf_uniqueid = iunique(sb, ROOT_I); |
529 | } | 522 | } |
530 | |||
531 | *pinode = cifs_new_inode(sb, pinum); | ||
532 | if (*pinode == NULL) { | ||
533 | rc = -ENOMEM; | ||
534 | goto cgii_exit; | ||
535 | } | ||
536 | } | ||
537 | inode = *pinode; | ||
538 | cifsInfo = CIFS_I(inode); | ||
539 | cifsInfo->cifsAttrs = attr; | ||
540 | cifsInfo->delete_pending = pfindData->DeletePending ? true : false; | ||
541 | cFYI(1, ("Old time %ld", cifsInfo->time)); | ||
542 | cifsInfo->time = jiffies; | ||
543 | cFYI(1, ("New time %ld", cifsInfo->time)); | ||
544 | |||
545 | /* blksize needs to be multiple of two. So safer to default to | ||
546 | blksize and blkbits set in superblock so 2**blkbits and blksize | ||
547 | will match rather than setting to: | ||
548 | (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ | ||
549 | |||
550 | /* Linux can not store file creation time so ignore it */ | ||
551 | if (pfindData->LastAccessTime) | ||
552 | inode->i_atime = cifs_NTtimeToUnix(pfindData->LastAccessTime); | ||
553 | else /* do not need to use current_fs_time - time not stored */ | ||
554 | inode->i_atime = CURRENT_TIME; | ||
555 | inode->i_mtime = cifs_NTtimeToUnix(pfindData->LastWriteTime); | ||
556 | inode->i_ctime = cifs_NTtimeToUnix(pfindData->ChangeTime); | ||
557 | cFYI(DBG2, ("Attributes came in as 0x%x", attr)); | ||
558 | if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { | ||
559 | inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; | ||
560 | inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; | ||
561 | } | ||
562 | |||
563 | /* get default inode mode */ | ||
564 | if (attr & ATTR_DIRECTORY) | ||
565 | default_mode = cifs_sb->mnt_dir_mode; | ||
566 | else | ||
567 | default_mode = cifs_sb->mnt_file_mode; | ||
568 | |||
569 | /* set permission bits */ | ||
570 | if (atomic_read(&cifsInfo->inUse) == 0 || | ||
571 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) | ||
572 | inode->i_mode = default_mode; | ||
573 | else { | ||
574 | /* just reenable write bits if !ATTR_READONLY */ | ||
575 | if ((inode->i_mode & S_IWUGO) == 0 && | ||
576 | (attr & ATTR_READONLY) == 0) | ||
577 | inode->i_mode |= (S_IWUGO & default_mode); | ||
578 | |||
579 | inode->i_mode &= ~S_IFMT; | ||
580 | } | ||
581 | /* clear write bits if ATTR_READONLY is set */ | ||
582 | if (attr & ATTR_READONLY) | ||
583 | inode->i_mode &= ~S_IWUGO; | ||
584 | |||
585 | /* set inode type */ | ||
586 | if ((attr & ATTR_SYSTEM) && | ||
587 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { | ||
588 | /* no need to fix endianness on 0 */ | ||
589 | if (pfindData->EndOfFile == 0) | ||
590 | inode->i_mode |= S_IFIFO; | ||
591 | else if (decode_sfu_inode(inode, | ||
592 | le64_to_cpu(pfindData->EndOfFile), | ||
593 | full_path, cifs_sb, xid)) | ||
594 | cFYI(1, ("unknown SFU file type\n")); | ||
595 | } else { | 523 | } else { |
596 | if (attr & ATTR_DIRECTORY) | 524 | fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid; |
597 | inode->i_mode |= S_IFDIR; | ||
598 | else | ||
599 | inode->i_mode |= S_IFREG; | ||
600 | } | 525 | } |
601 | 526 | ||
602 | cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile); | 527 | /* query for SFU type info if supported and needed */ |
603 | spin_lock(&inode->i_lock); | 528 | if (fattr.cf_cifsattrs & ATTR_SYSTEM && |
604 | if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) { | 529 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { |
605 | /* can not safely shrink the file size here if the | 530 | tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid); |
606 | client is writing to it due to potential races */ | 531 | if (tmprc) |
607 | i_size_write(inode, cifsInfo->server_eof); | 532 | cFYI(1, ("cifs_sfu_type failed: %d", tmprc)); |
608 | |||
609 | /* 512 bytes (2**9) is the fake blocksize that must be | ||
610 | used for this calculation */ | ||
611 | inode->i_blocks = (512 - 1 + le64_to_cpu( | ||
612 | pfindData->AllocationSize)) >> 9; | ||
613 | } | 533 | } |
614 | spin_unlock(&inode->i_lock); | ||
615 | 534 | ||
616 | inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); | ||
617 | |||
618 | /* BB fill in uid and gid here? with help from winbind? | ||
619 | or retrieve from NTFS stream extended attribute */ | ||
620 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 535 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
621 | /* fill in 0777 bits from ACL */ | 536 | /* fill in 0777 bits from ACL */ |
622 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 537 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
623 | cFYI(1, ("Getting mode bits from ACL")); | 538 | cFYI(1, ("Getting mode bits from ACL")); |
624 | acl_to_uid_mode(cifs_sb, inode, full_path, pfid); | 539 | cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid); |
625 | } | 540 | } |
626 | #endif | 541 | #endif |
627 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | ||
628 | /* fill in remaining high mode bits e.g. SUID, VTX */ | ||
629 | get_sfu_mode(inode, full_path, cifs_sb, xid); | ||
630 | } else if (atomic_read(&cifsInfo->inUse) == 0) { | ||
631 | inode->i_uid = cifs_sb->mnt_uid; | ||
632 | inode->i_gid = cifs_sb->mnt_gid; | ||
633 | /* set so we do not keep refreshing these fields with | ||
634 | bad data after user has changed them in memory */ | ||
635 | atomic_set(&cifsInfo->inUse, 1); | ||
636 | } | ||
637 | |||
638 | cifs_set_ops(inode, is_dfs_referral); | ||
639 | |||
640 | 542 | ||
543 | /* fill in remaining high mode bits e.g. SUID, VTX */ | ||
544 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | ||
545 | cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); | ||
641 | 546 | ||
547 | if (!*pinode) { | ||
548 | *pinode = cifs_iget(sb, &fattr); | ||
549 | if (!*pinode) | ||
550 | rc = -ENOMEM; | ||
551 | } else { | ||
552 | cifs_fattr_to_inode(*pinode, &fattr); | ||
553 | } | ||
642 | 554 | ||
643 | cgii_exit: | 555 | cgii_exit: |
644 | kfree(buf); | 556 | kfree(buf); |
@@ -753,21 +665,14 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | |||
753 | return ERR_PTR(-ENOMEM); | 665 | return ERR_PTR(-ENOMEM); |
754 | 666 | ||
755 | xid = GetXid(); | 667 | xid = GetXid(); |
756 | if (cifs_sb->tcon->unix_ext) { | 668 | if (cifs_sb->tcon->unix_ext) |
757 | rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); | 669 | rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); |
758 | if (!inode) | 670 | else |
759 | return ERR_PTR(-ENOMEM); | 671 | rc = cifs_get_inode_info(&inode, full_path, NULL, sb, |
760 | } else { | ||
761 | inode = iget_locked(sb, ino); | ||
762 | if (!inode) | ||
763 | return ERR_PTR(-ENOMEM); | ||
764 | if (!(inode->i_state & I_NEW)) | ||
765 | return inode; | ||
766 | |||
767 | rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb, | ||
768 | xid, NULL); | 672 | xid, NULL); |
769 | unlock_new_inode(inode); | 673 | |
770 | } | 674 | if (!inode) |
675 | return ERR_PTR(-ENOMEM); | ||
771 | 676 | ||
772 | if (rc && cifs_sb->tcon->ipc) { | 677 | if (rc && cifs_sb->tcon->ipc) { |
773 | cFYI(1, ("ipc connection - fake read inode")); | 678 | cFYI(1, ("ipc connection - fake read inode")); |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 231aa6953f83..f823a4a208a7 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -112,239 +112,74 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
112 | return dentry; | 112 | return dentry; |
113 | } | 113 | } |
114 | 114 | ||
115 | /* Returns 1 if new inode created, 2 if both dentry and inode were */ | 115 | static void |
116 | /* Might check in the future if inode number changed so we can rehash inode */ | 116 | cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) |
117 | static int | ||
118 | construct_dentry(struct qstr *qstring, struct file *file, | ||
119 | struct inode **ptmp_inode, struct dentry **pnew_dentry, | ||
120 | __u64 *inum) | ||
121 | { | 117 | { |
122 | struct dentry *tmp_dentry = NULL; | 118 | fattr->cf_uid = cifs_sb->mnt_uid; |
123 | struct super_block *sb = file->f_path.dentry->d_sb; | 119 | fattr->cf_gid = cifs_sb->mnt_gid; |
124 | int rc = 0; | ||
125 | 120 | ||
126 | cFYI(1, ("For %s", qstring->name)); | 121 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { |
127 | 122 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; | |
128 | tmp_dentry = d_lookup(file->f_path.dentry, qstring); | 123 | fattr->cf_dtype = DT_DIR; |
129 | if (tmp_dentry) { | ||
130 | /* BB: overwrite old name? i.e. tmp_dentry->d_name and | ||
131 | * tmp_dentry->d_name.len?? | ||
132 | */ | ||
133 | cFYI(0, ("existing dentry with inode 0x%p", | ||
134 | tmp_dentry->d_inode)); | ||
135 | *ptmp_inode = tmp_dentry->d_inode; | ||
136 | if (*ptmp_inode == NULL) { | ||
137 | *ptmp_inode = cifs_new_inode(sb, inum); | ||
138 | if (*ptmp_inode == NULL) | ||
139 | return rc; | ||
140 | rc = 1; | ||
141 | } | ||
142 | } else { | 124 | } else { |
143 | tmp_dentry = d_alloc(file->f_path.dentry, qstring); | 125 | fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; |
144 | if (tmp_dentry == NULL) { | 126 | fattr->cf_dtype = DT_REG; |
145 | cERROR(1, ("Failed allocating dentry")); | ||
146 | *ptmp_inode = NULL; | ||
147 | return rc; | ||
148 | } | ||
149 | |||
150 | if (CIFS_SB(sb)->tcon->nocase) | ||
151 | tmp_dentry->d_op = &cifs_ci_dentry_ops; | ||
152 | else | ||
153 | tmp_dentry->d_op = &cifs_dentry_ops; | ||
154 | |||
155 | *ptmp_inode = cifs_new_inode(sb, inum); | ||
156 | if (*ptmp_inode == NULL) | ||
157 | return rc; | ||
158 | rc = 2; | ||
159 | } | ||
160 | |||
161 | tmp_dentry->d_time = jiffies; | ||
162 | *pnew_dentry = tmp_dentry; | ||
163 | return rc; | ||
164 | } | ||
165 | |||
166 | static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, | ||
167 | char *buf, unsigned int *pobject_type, int isNewInode) | ||
168 | { | ||
169 | loff_t local_size; | ||
170 | struct timespec local_mtime; | ||
171 | |||
172 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | ||
173 | struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); | ||
174 | __u32 attr; | ||
175 | __u64 allocation_size; | ||
176 | __u64 end_of_file; | ||
177 | umode_t default_mode; | ||
178 | |||
179 | /* save mtime and size */ | ||
180 | local_mtime = tmp_inode->i_mtime; | ||
181 | local_size = tmp_inode->i_size; | ||
182 | |||
183 | if (new_buf_type) { | ||
184 | FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf; | ||
185 | |||
186 | attr = le32_to_cpu(pfindData->ExtFileAttributes); | ||
187 | allocation_size = le64_to_cpu(pfindData->AllocationSize); | ||
188 | end_of_file = le64_to_cpu(pfindData->EndOfFile); | ||
189 | tmp_inode->i_atime = | ||
190 | cifs_NTtimeToUnix(pfindData->LastAccessTime); | ||
191 | tmp_inode->i_mtime = | ||
192 | cifs_NTtimeToUnix(pfindData->LastWriteTime); | ||
193 | tmp_inode->i_ctime = | ||
194 | cifs_NTtimeToUnix(pfindData->ChangeTime); | ||
195 | } else { /* legacy, OS2 and DOS style */ | ||
196 | int offset = cifs_sb->tcon->ses->server->timeAdj; | ||
197 | FIND_FILE_STANDARD_INFO *pfindData = | ||
198 | (FIND_FILE_STANDARD_INFO *)buf; | ||
199 | |||
200 | tmp_inode->i_mtime = cnvrtDosUnixTm(pfindData->LastWriteDate, | ||
201 | pfindData->LastWriteTime, | ||
202 | offset); | ||
203 | tmp_inode->i_atime = cnvrtDosUnixTm(pfindData->LastAccessDate, | ||
204 | pfindData->LastAccessTime, | ||
205 | offset); | ||
206 | tmp_inode->i_ctime = cnvrtDosUnixTm(pfindData->LastWriteDate, | ||
207 | pfindData->LastWriteTime, | ||
208 | offset); | ||
209 | attr = le16_to_cpu(pfindData->Attributes); | ||
210 | allocation_size = le32_to_cpu(pfindData->AllocationSize); | ||
211 | end_of_file = le32_to_cpu(pfindData->DataSize); | ||
212 | } | ||
213 | |||
214 | /* Linux can not store file creation time unfortunately so ignore it */ | ||
215 | |||
216 | cifsInfo->cifsAttrs = attr; | ||
217 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
218 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | ||
219 | /* get more accurate mode via ACL - so force inode refresh */ | ||
220 | cifsInfo->time = 0; | ||
221 | } else | ||
222 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
223 | cifsInfo->time = jiffies; | ||
224 | |||
225 | /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ | ||
226 | /* 2767 perms - indicate mandatory locking */ | ||
227 | /* BB fill in uid and gid here? with help from winbind? | ||
228 | or retrieve from NTFS stream extended attribute */ | ||
229 | if (atomic_read(&cifsInfo->inUse) == 0) { | ||
230 | tmp_inode->i_uid = cifs_sb->mnt_uid; | ||
231 | tmp_inode->i_gid = cifs_sb->mnt_gid; | ||
232 | } | 127 | } |
233 | 128 | ||
234 | if (attr & ATTR_DIRECTORY) | 129 | if (fattr->cf_cifsattrs & ATTR_READONLY) |
235 | default_mode = cifs_sb->mnt_dir_mode; | 130 | fattr->cf_mode &= ~S_IWUGO; |
236 | else | ||
237 | default_mode = cifs_sb->mnt_file_mode; | ||
238 | |||
239 | /* set initial permissions */ | ||
240 | if ((atomic_read(&cifsInfo->inUse) == 0) || | ||
241 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) | ||
242 | tmp_inode->i_mode = default_mode; | ||
243 | else { | ||
244 | /* just reenable write bits if !ATTR_READONLY */ | ||
245 | if ((tmp_inode->i_mode & S_IWUGO) == 0 && | ||
246 | (attr & ATTR_READONLY) == 0) | ||
247 | tmp_inode->i_mode |= (S_IWUGO & default_mode); | ||
248 | |||
249 | tmp_inode->i_mode &= ~S_IFMT; | ||
250 | } | ||
251 | |||
252 | /* clear write bits if ATTR_READONLY is set */ | ||
253 | if (attr & ATTR_READONLY) | ||
254 | tmp_inode->i_mode &= ~S_IWUGO; | ||
255 | 131 | ||
256 | /* set inode type */ | 132 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL && |
257 | if ((attr & ATTR_SYSTEM) && | 133 | fattr->cf_cifsattrs & ATTR_SYSTEM) { |
258 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { | 134 | if (fattr->cf_eof == 0) { |
259 | if (end_of_file == 0) { | 135 | fattr->cf_mode &= ~S_IFMT; |
260 | tmp_inode->i_mode |= S_IFIFO; | 136 | fattr->cf_mode |= S_IFIFO; |
261 | *pobject_type = DT_FIFO; | 137 | fattr->cf_dtype = DT_FIFO; |
262 | } else { | 138 | } else { |
263 | /* | 139 | /* |
264 | * trying to get the type can be slow, so just call | 140 | * trying to get the type and mode via SFU can be slow, |
265 | * this a regular file for now, and mark for reval | 141 | * so just call those regular files for now, and mark |
142 | * for reval | ||
266 | */ | 143 | */ |
267 | tmp_inode->i_mode |= S_IFREG; | 144 | fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; |
268 | *pobject_type = DT_REG; | ||
269 | cifsInfo->time = 0; | ||
270 | } | ||
271 | } else { | ||
272 | if (attr & ATTR_DIRECTORY) { | ||
273 | tmp_inode->i_mode |= S_IFDIR; | ||
274 | *pobject_type = DT_DIR; | ||
275 | } else { | ||
276 | tmp_inode->i_mode |= S_IFREG; | ||
277 | *pobject_type = DT_REG; | ||
278 | } | 145 | } |
279 | } | 146 | } |
147 | } | ||
280 | 148 | ||
281 | /* can not fill in nlink here as in qpathinfo version and Unx search */ | 149 | void |
282 | if (atomic_read(&cifsInfo->inUse) == 0) | 150 | cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info, |
283 | atomic_set(&cifsInfo->inUse, 1); | 151 | struct cifs_sb_info *cifs_sb) |
152 | { | ||
153 | memset(fattr, 0, sizeof(*fattr)); | ||
154 | fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); | ||
155 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); | ||
156 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | ||
157 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); | ||
158 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); | ||
159 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); | ||
160 | |||
161 | cifs_fill_common_info(fattr, cifs_sb); | ||
162 | } | ||
284 | 163 | ||
285 | cifsInfo->server_eof = end_of_file; | 164 | void |
286 | spin_lock(&tmp_inode->i_lock); | 165 | cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, |
287 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | 166 | struct cifs_sb_info *cifs_sb) |
288 | /* can not safely change the file size here if the | 167 | { |
289 | client is writing to it due to potential races */ | 168 | int offset = cifs_sb->tcon->ses->server->timeAdj; |
290 | i_size_write(tmp_inode, end_of_file); | ||
291 | 169 | ||
292 | /* 512 bytes (2**9) is the fake blocksize that must be used */ | 170 | memset(fattr, 0, sizeof(*fattr)); |
293 | /* for this calculation, even though the reported blocksize is larger */ | 171 | fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, |
294 | tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; | 172 | info->LastAccessTime, offset); |
295 | } | 173 | fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate, |
296 | spin_unlock(&tmp_inode->i_lock); | 174 | info->LastWriteTime, offset); |
297 | 175 | fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate, | |
298 | if (allocation_size < end_of_file) | 176 | info->LastWriteTime, offset); |
299 | cFYI(1, ("May be sparse file, allocation less than file size")); | 177 | |
300 | cFYI(1, ("File Size %ld and blocks %llu", | 178 | fattr->cf_cifsattrs = le16_to_cpu(info->Attributes); |
301 | (unsigned long)tmp_inode->i_size, | 179 | fattr->cf_bytes = le32_to_cpu(info->AllocationSize); |
302 | (unsigned long long)tmp_inode->i_blocks)); | 180 | fattr->cf_eof = le32_to_cpu(info->DataSize); |
303 | if (S_ISREG(tmp_inode->i_mode)) { | 181 | |
304 | cFYI(1, ("File inode")); | 182 | cifs_fill_common_info(fattr, cifs_sb); |
305 | tmp_inode->i_op = &cifs_file_inode_ops; | ||
306 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { | ||
307 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
308 | tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; | ||
309 | else | ||
310 | tmp_inode->i_fop = &cifs_file_direct_ops; | ||
311 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
312 | tmp_inode->i_fop = &cifs_file_nobrl_ops; | ||
313 | else | ||
314 | tmp_inode->i_fop = &cifs_file_ops; | ||
315 | |||
316 | if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | ||
317 | (cifs_sb->tcon->ses->server->maxBuf < | ||
318 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) | ||
319 | tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; | ||
320 | else | ||
321 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
322 | |||
323 | if (isNewInode) | ||
324 | return; /* No sense invalidating pages for new inode | ||
325 | since have not started caching readahead file | ||
326 | data yet */ | ||
327 | |||
328 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | ||
329 | (local_size == tmp_inode->i_size)) { | ||
330 | cFYI(1, ("inode exists but unchanged")); | ||
331 | } else { | ||
332 | /* file may have changed on server */ | ||
333 | cFYI(1, ("invalidate inode, readdir detected change")); | ||
334 | invalidate_remote_inode(tmp_inode); | ||
335 | } | ||
336 | } else if (S_ISDIR(tmp_inode->i_mode)) { | ||
337 | cFYI(1, ("Directory inode")); | ||
338 | tmp_inode->i_op = &cifs_dir_inode_ops; | ||
339 | tmp_inode->i_fop = &cifs_dir_ops; | ||
340 | } else if (S_ISLNK(tmp_inode->i_mode)) { | ||
341 | cFYI(1, ("Symbolic Link inode")); | ||
342 | tmp_inode->i_op = &cifs_symlink_inode_ops; | ||
343 | } else { | ||
344 | cFYI(1, ("Init special inode")); | ||
345 | init_special_inode(tmp_inode, tmp_inode->i_mode, | ||
346 | tmp_inode->i_rdev); | ||
347 | } | ||
348 | } | 183 | } |
349 | 184 | ||
350 | /* BB eventually need to add the following helper function to | 185 | /* BB eventually need to add the following helper function to |
@@ -846,11 +681,10 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, | |||
846 | int rc = 0; | 681 | int rc = 0; |
847 | struct qstr qstring; | 682 | struct qstr qstring; |
848 | struct cifsFileInfo *pCifsF; | 683 | struct cifsFileInfo *pCifsF; |
849 | unsigned int obj_type; | 684 | u64 inum; |
850 | __u64 inum; | ||
851 | ino_t ino; | 685 | ino_t ino; |
686 | struct super_block *sb; | ||
852 | struct cifs_sb_info *cifs_sb; | 687 | struct cifs_sb_info *cifs_sb; |
853 | struct inode *tmp_inode; | ||
854 | struct dentry *tmp_dentry; | 688 | struct dentry *tmp_dentry; |
855 | struct cifs_fattr fattr; | 689 | struct cifs_fattr fattr; |
856 | 690 | ||
@@ -870,71 +704,53 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, | |||
870 | if (rc != 0) | 704 | if (rc != 0) |
871 | return 0; | 705 | return 0; |
872 | 706 | ||
873 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 707 | sb = file->f_path.dentry->d_sb; |
708 | cifs_sb = CIFS_SB(sb); | ||
874 | 709 | ||
875 | qstring.name = scratch_buf; | 710 | qstring.name = scratch_buf; |
876 | rc = cifs_get_name_from_search_buf(&qstring, pfindEntry, | 711 | rc = cifs_get_name_from_search_buf(&qstring, pfindEntry, |
877 | pCifsF->srch_inf.info_level, | 712 | pCifsF->srch_inf.info_level, |
878 | pCifsF->srch_inf.unicode, cifs_sb, | 713 | pCifsF->srch_inf.unicode, cifs_sb, |
879 | max_len, | 714 | max_len, &inum /* returned */); |
880 | &inum /* returned */); | ||
881 | 715 | ||
882 | if (rc) | 716 | if (rc) |
883 | return rc; | 717 | return rc; |
884 | 718 | ||
885 | /* only these two infolevels return valid inode numbers */ | 719 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) |
886 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { | ||
887 | cifs_unix_basic_to_fattr(&fattr, | 720 | cifs_unix_basic_to_fattr(&fattr, |
888 | &((FILE_UNIX_INFO *) pfindEntry)->basic, | 721 | &((FILE_UNIX_INFO *) pfindEntry)->basic, |
889 | cifs_sb); | 722 | cifs_sb); |
890 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, | 723 | else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) |
891 | &fattr); | 724 | cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *) |
892 | obj_type = fattr.cf_dtype; | 725 | pfindEntry, cifs_sb); |
893 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); | 726 | else |
894 | } else { | 727 | cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *) |
895 | if (pCifsF->srch_inf.info_level == | 728 | pfindEntry, cifs_sb); |
896 | SMB_FIND_FILE_ID_FULL_DIR_INFO) | ||
897 | rc = construct_dentry(&qstring, file, &tmp_inode, | ||
898 | &tmp_dentry, &inum); | ||
899 | else | ||
900 | rc = construct_dentry(&qstring, file, &tmp_inode, | ||
901 | &tmp_dentry, NULL); | ||
902 | |||
903 | if ((tmp_inode == NULL) || (tmp_dentry == NULL)) { | ||
904 | rc = -ENOMEM; | ||
905 | goto out; | ||
906 | } | ||
907 | |||
908 | /* we pass in rc below, indicating whether it is a new inode, | ||
909 | * so we can figure out whether to invalidate the inode cached | ||
910 | * data if the file has changed | ||
911 | */ | ||
912 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) | ||
913 | fill_in_inode(tmp_inode, 0, pfindEntry, &obj_type, rc); | ||
914 | else | ||
915 | fill_in_inode(tmp_inode, 1, pfindEntry, &obj_type, rc); | ||
916 | 729 | ||
917 | /* new inode - needs to be tied to dentry */ | 730 | /* FIXME: make _to_fattr functions fill this out */ |
918 | if (rc) { | 731 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO) |
919 | d_instantiate(tmp_dentry, tmp_inode); | 732 | fattr.cf_uniqueid = inum; |
920 | if (rc == 2) | 733 | else |
921 | d_rehash(tmp_dentry); | 734 | fattr.cf_uniqueid = iunique(sb, ROOT_I); |
922 | } | ||
923 | 735 | ||
924 | ino = cifs_uniqueid_to_ino_t(tmp_inode->i_ino); | 736 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); |
925 | } | 737 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); |
926 | 738 | ||
927 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, | 739 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, |
928 | ino, obj_type); | 740 | ino, fattr.cf_dtype); |
741 | |||
742 | /* | ||
743 | * we can not return filldir errors to the caller since they are | ||
744 | * "normal" when the stat blocksize is too small - we return remapped | ||
745 | * error instead | ||
746 | * | ||
747 | * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above | ||
748 | * case already. Why should we be clobbering other errors from it? | ||
749 | */ | ||
929 | if (rc) { | 750 | if (rc) { |
930 | cFYI(1, ("filldir rc = %d", rc)); | 751 | cFYI(1, ("filldir rc = %d", rc)); |
931 | /* we can not return filldir errors to the caller | ||
932 | since they are "normal" when the stat blocksize | ||
933 | is too small - we return remapped error instead */ | ||
934 | rc = -EOVERFLOW; | 752 | rc = -EOVERFLOW; |
935 | } | 753 | } |
936 | |||
937 | out: | ||
938 | dput(tmp_dentry); | 754 | dput(tmp_dentry); |
939 | return rc; | 755 | return rc; |
940 | } | 756 | } |