aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r--fs/cifs/inode.c567
1 files changed, 303 insertions, 264 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index fcbdbb6ad7bf..722be543ceec 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -161,118 +161,115 @@ static void cifs_unix_info_to_inode(struct inode *inode,
161 spin_unlock(&inode->i_lock); 161 spin_unlock(&inode->i_lock);
162} 162}
163 163
164static const unsigned char *cifs_get_search_path(struct cifs_sb_info *cifs_sb,
165 const char *search_path)
166{
167 int tree_len;
168 int path_len;
169 int i;
170 char *tmp_path;
171 struct cifsTconInfo *pTcon = cifs_sb->tcon;
172
173 if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
174 return search_path;
175
176 /* use full path name for working with DFS */
177 tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1);
178 path_len = strnlen(search_path, MAX_PATHCONF);
179 164
180 tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL); 165/*
181 if (tmp_path == NULL) 166 * Needed to setup inode data for the directory which is the
182 return search_path; 167 * junction to the new submount (ie to setup the fake directory
168 * which represents a DFS referral)
169 */
170static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
171 struct super_block *sb)
172{
173 struct inode *pinode = NULL;
174
175 memset(pfnd_dat, 0, sizeof(FILE_UNIX_BASIC_INFO));
176
177/* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
178 __le64 pfnd_dat->NumOfBytes = cpu_to_le64(0);
179 __u64 UniqueId = 0; */
180 pfnd_dat->LastStatusChange =
181 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
182 pfnd_dat->LastAccessTime =
183 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
184 pfnd_dat->LastModificationTime =
185 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
186 pfnd_dat->Type = cpu_to_le32(UNIX_DIR);
187 pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU);
188 pfnd_dat->Nlinks = cpu_to_le64(2);
189 if (sb->s_root)
190 pinode = sb->s_root->d_inode;
191 if (pinode == NULL)
192 return;
183 193
184 strncpy(tmp_path, pTcon->treeName, tree_len); 194 /* fill in default values for the remaining based on root
185 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) 195 inode since we can not query the server for this inode info */
186 for (i = 0; i < tree_len; i++) { 196 pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev));
187 if (tmp_path[i] == '\\') 197 pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev));
188 tmp_path[i] = '/'; 198 pfnd_dat->Uid = cpu_to_le64(pinode->i_uid);
189 } 199 pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
190 strncpy(tmp_path+tree_len, search_path, path_len);
191 tmp_path[tree_len+path_len] = 0;
192 return tmp_path;
193} 200}
194 201
195int cifs_get_inode_info_unix(struct inode **pinode, 202int cifs_get_inode_info_unix(struct inode **pinode,
196 const unsigned char *search_path, struct super_block *sb, int xid) 203 const unsigned char *full_path, struct super_block *sb, int xid)
197{ 204{
198 int rc = 0; 205 int rc = 0;
199 FILE_UNIX_BASIC_INFO findData; 206 FILE_UNIX_BASIC_INFO find_data;
200 struct cifsTconInfo *pTcon; 207 struct cifsTconInfo *pTcon;
201 struct inode *inode; 208 struct inode *inode;
202 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 209 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
203 const unsigned char *full_path;
204 bool is_dfs_referral = false; 210 bool is_dfs_referral = false;
211 struct cifsInodeInfo *cifsInfo;
212 __u64 num_of_bytes;
213 __u64 end_of_file;
205 214
206 pTcon = cifs_sb->tcon; 215 pTcon = cifs_sb->tcon;
207 cFYI(1, ("Getting info on %s", search_path)); 216 cFYI(1, ("Getting info on %s", full_path));
208
209 full_path = cifs_get_search_path(cifs_sb, search_path);
210 217
211try_again_CIFSSMBUnixQPathInfo:
212 /* could have done a find first instead but this returns more info */ 218 /* could have done a find first instead but this returns more info */
213 rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData, 219 rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data,
214 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 220 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
215 CIFS_MOUNT_MAP_SPECIAL_CHR); 221 CIFS_MOUNT_MAP_SPECIAL_CHR);
216/* dump_mem("\nUnixQPathInfo return data", &findData,
217 sizeof(findData)); */
218 if (rc) { 222 if (rc) {
219 if (rc == -EREMOTE && !is_dfs_referral) { 223 if (rc == -EREMOTE && !is_dfs_referral) {
220 is_dfs_referral = true; 224 is_dfs_referral = true;
221 if (full_path != search_path) { 225 cFYI(DBG2, ("DFS ref"));
222 kfree(full_path); 226 /* for DFS, server does not give us real inode data */
223 full_path = search_path; 227 fill_fake_finddataunix(&find_data, sb);
224 } 228 rc = 0;
225 goto try_again_CIFSSMBUnixQPathInfo;
226 } 229 }
227 goto cgiiu_exit; 230 }
228 } else { 231 num_of_bytes = le64_to_cpu(find_data.NumOfBytes);
229 struct cifsInodeInfo *cifsInfo; 232 end_of_file = le64_to_cpu(find_data.EndOfFile);
230 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
231 __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
232 233
233 /* get new inode */ 234 /* get new inode */
235 if (*pinode == NULL) {
236 *pinode = new_inode(sb);
234 if (*pinode == NULL) { 237 if (*pinode == NULL) {
235 *pinode = new_inode(sb); 238 rc = -ENOMEM;
236 if (*pinode == NULL) { 239 goto cgiiu_exit;
237 rc = -ENOMEM;
238 goto cgiiu_exit;
239 }
240 /* Is an i_ino of zero legal? */
241 /* Are there sanity checks we can use to ensure that
242 the server is really filling in that field? */
243 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
244 (*pinode)->i_ino =
245 (unsigned long)findData.UniqueId;
246 } /* note ino incremented to unique num in new_inode */
247 if (sb->s_flags & MS_NOATIME)
248 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
249
250 insert_inode_hash(*pinode);
251 } 240 }
241 /* Is an i_ino of zero legal? */
242 /* note ino incremented to unique num in new_inode */
243 /* Are there sanity checks we can use to ensure that
244 the server is really filling in that field? */
245 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
246 (*pinode)->i_ino = (unsigned long)find_data.UniqueId;
252 247
253 inode = *pinode; 248 if (sb->s_flags & MS_NOATIME)
254 cifsInfo = CIFS_I(inode); 249 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
255 250
256 cFYI(1, ("Old time %ld", cifsInfo->time)); 251 insert_inode_hash(*pinode);
257 cifsInfo->time = jiffies; 252 }
258 cFYI(1, ("New time %ld", cifsInfo->time)); 253
259 /* this is ok to set on every inode revalidate */ 254 inode = *pinode;
260 atomic_set(&cifsInfo->inUse, 1); 255 cifsInfo = CIFS_I(inode);
261 256
262 cifs_unix_info_to_inode(inode, &findData, 0); 257 cFYI(1, ("Old time %ld", cifsInfo->time));
258 cifsInfo->time = jiffies;
259 cFYI(1, ("New time %ld", cifsInfo->time));
260 /* this is ok to set on every inode revalidate */
261 atomic_set(&cifsInfo->inUse, 1);
263 262
263 cifs_unix_info_to_inode(inode, &find_data, 0);
264 264
265 if (num_of_bytes < end_of_file) 265 if (num_of_bytes < end_of_file)
266 cFYI(1, ("allocation size less than end of file")); 266 cFYI(1, ("allocation size less than end of file"));
267 cFYI(1, ("Size %ld and blocks %llu", 267 cFYI(1, ("Size %ld and blocks %llu",
268 (unsigned long) inode->i_size, 268 (unsigned long) inode->i_size,
269 (unsigned long long)inode->i_blocks)); 269 (unsigned long long)inode->i_blocks));
270 270
271 cifs_set_ops(inode, is_dfs_referral); 271 cifs_set_ops(inode, is_dfs_referral);
272 }
273cgiiu_exit: 272cgiiu_exit:
274 if (full_path != search_path)
275 kfree(full_path);
276 return rc; 273 return rc;
277} 274}
278 275
@@ -379,21 +376,52 @@ static int get_sfu_mode(struct inode *inode,
379#endif 376#endif
380} 377}
381 378
379/*
380 * Needed to setup inode data for the directory which is the
381 * junction to the new submount (ie to setup the fake directory
382 * which represents a DFS referral)
383 */
384static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat,
385 struct super_block *sb)
386{
387 memset(pfnd_dat, 0, sizeof(FILE_ALL_INFO));
388
389/* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0);
390 __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
391 __u8 pfnd_dat->DeletePending = 0;
392 __u8 pfnd_data->Directory = 0;
393 __le32 pfnd_dat->EASize = 0;
394 __u64 pfnd_dat->IndexNumber = 0;
395 __u64 pfnd_dat->IndexNumber1 = 0; */
396 pfnd_dat->CreationTime =
397 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
398 pfnd_dat->LastAccessTime =
399 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
400 pfnd_dat->LastWriteTime =
401 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
402 pfnd_dat->ChangeTime =
403 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
404 pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY);
405 pfnd_dat->NumberOfLinks = cpu_to_le32(2);
406}
407
382int cifs_get_inode_info(struct inode **pinode, 408int cifs_get_inode_info(struct inode **pinode,
383 const unsigned char *search_path, FILE_ALL_INFO *pfindData, 409 const unsigned char *full_path, FILE_ALL_INFO *pfindData,
384 struct super_block *sb, int xid, const __u16 *pfid) 410 struct super_block *sb, int xid, const __u16 *pfid)
385{ 411{
386 int rc = 0; 412 int rc = 0;
413 __u32 attr;
414 struct cifsInodeInfo *cifsInfo;
387 struct cifsTconInfo *pTcon; 415 struct cifsTconInfo *pTcon;
388 struct inode *inode; 416 struct inode *inode;
389 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 417 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
390 const unsigned char *full_path = NULL;
391 char *buf = NULL; 418 char *buf = NULL;
392 bool adjustTZ = false; 419 bool adjustTZ = false;
393 bool is_dfs_referral = false; 420 bool is_dfs_referral = false;
421 umode_t default_mode;
394 422
395 pTcon = cifs_sb->tcon; 423 pTcon = cifs_sb->tcon;
396 cFYI(1, ("Getting info on %s", search_path)); 424 cFYI(1, ("Getting info on %s", full_path));
397 425
398 if ((pfindData == NULL) && (*pinode != NULL)) { 426 if ((pfindData == NULL) && (*pinode != NULL)) {
399 if (CIFS_I(*pinode)->clientCanCacheRead) { 427 if (CIFS_I(*pinode)->clientCanCacheRead) {
@@ -409,9 +437,6 @@ int cifs_get_inode_info(struct inode **pinode,
409 return -ENOMEM; 437 return -ENOMEM;
410 pfindData = (FILE_ALL_INFO *)buf; 438 pfindData = (FILE_ALL_INFO *)buf;
411 439
412 full_path = cifs_get_search_path(cifs_sb, search_path);
413
414try_again_CIFSSMBQPathInfo:
415 /* could do find first instead but this returns more info */ 440 /* could do find first instead but this returns more info */
416 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, 441 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
417 0 /* not legacy */, 442 0 /* not legacy */,
@@ -429,178 +454,163 @@ try_again_CIFSSMBQPathInfo:
429 } 454 }
430 } 455 }
431 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ 456 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
432 if (rc) { 457 if (rc == -EREMOTE) {
433 if (rc == -EREMOTE && !is_dfs_referral) { 458 is_dfs_referral = true;
434 is_dfs_referral = true; 459 fill_fake_finddata(pfindData, sb);
435 if (full_path != search_path) { 460 rc = 0;
436 kfree(full_path); 461 } else if (rc)
437 full_path = search_path;
438 }
439 goto try_again_CIFSSMBQPathInfo;
440 }
441 goto cgii_exit; 462 goto cgii_exit;
442 } else {
443 struct cifsInodeInfo *cifsInfo;
444 __u32 attr = le32_to_cpu(pfindData->Attributes);
445
446 /* get new inode */
447 if (*pinode == NULL) {
448 *pinode = new_inode(sb);
449 if (*pinode == NULL) {
450 rc = -ENOMEM;
451 goto cgii_exit;
452 }
453 /* Is an i_ino of zero legal? Can we use that to check
454 if the server supports returning inode numbers? Are
455 there other sanity checks we can use to ensure that
456 the server is really filling in that field? */
457
458 /* We can not use the IndexNumber field by default from
459 Windows or Samba (in ALL_INFO buf) but we can request
460 it explicitly. It may not be unique presumably if
461 the server has multiple devices mounted under one
462 share */
463 463
464 /* There may be higher info levels that work but are 464 attr = le32_to_cpu(pfindData->Attributes);
465 there Windows server or network appliances for which
466 IndexNumber field is not guaranteed unique? */
467 465
468 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { 466 /* get new inode */
469 int rc1 = 0; 467 if (*pinode == NULL) {
470 __u64 inode_num; 468 *pinode = new_inode(sb);
471 469 if (*pinode == NULL) {
472 rc1 = CIFSGetSrvInodeNumber(xid, pTcon, 470 rc = -ENOMEM;
473 search_path, &inode_num, 471 goto cgii_exit;
472 }
473 /* Is an i_ino of zero legal? Can we use that to check
474 if the server supports returning inode numbers? Are
475 there other sanity checks we can use to ensure that
476 the server is really filling in that field? */
477
478 /* We can not use the IndexNumber field by default from
479 Windows or Samba (in ALL_INFO buf) but we can request
480 it explicitly. It may not be unique presumably if
481 the server has multiple devices mounted under one share */
482
483 /* There may be higher info levels that work but are
484 there Windows server or network appliances for which
485 IndexNumber field is not guaranteed unique? */
486
487 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
488 int rc1 = 0;
489 __u64 inode_num;
490
491 rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
492 full_path, &inode_num,
474 cifs_sb->local_nls, 493 cifs_sb->local_nls,
475 cifs_sb->mnt_cifs_flags & 494 cifs_sb->mnt_cifs_flags &
476 CIFS_MOUNT_MAP_SPECIAL_CHR); 495 CIFS_MOUNT_MAP_SPECIAL_CHR);
477 if (rc1) { 496 if (rc1) {
478 cFYI(1, ("GetSrvInodeNum rc %d", rc1)); 497 cFYI(1, ("GetSrvInodeNum rc %d", rc1));
479 /* BB EOPNOSUPP disable SERVER_INUM? */ 498 /* BB EOPNOSUPP disable SERVER_INUM? */
480 } else /* do we need cast or hash to ino? */ 499 } else /* do we need cast or hash to ino? */
481 (*pinode)->i_ino = inode_num; 500 (*pinode)->i_ino = inode_num;
482 } /* else ino incremented to unique num in new_inode*/ 501 } /* else ino incremented to unique num in new_inode*/
483 if (sb->s_flags & MS_NOATIME) 502 if (sb->s_flags & MS_NOATIME)
484 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; 503 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
485 insert_inode_hash(*pinode); 504 insert_inode_hash(*pinode);
486 } 505 }
487 inode = *pinode; 506 inode = *pinode;
488 cifsInfo = CIFS_I(inode); 507 cifsInfo = CIFS_I(inode);
489 cifsInfo->cifsAttrs = attr; 508 cifsInfo->cifsAttrs = attr;
490 cFYI(1, ("Old time %ld", cifsInfo->time)); 509 cFYI(1, ("Old time %ld", cifsInfo->time));
491 cifsInfo->time = jiffies; 510 cifsInfo->time = jiffies;
492 cFYI(1, ("New time %ld", cifsInfo->time)); 511 cFYI(1, ("New time %ld", cifsInfo->time));
493 512
494 /* blksize needs to be multiple of two. So safer to default to 513 /* blksize needs to be multiple of two. So safer to default to
495 blksize and blkbits set in superblock so 2**blkbits and blksize 514 blksize and blkbits set in superblock so 2**blkbits and blksize
496 will match rather than setting to: 515 will match rather than setting to:
497 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ 516 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
498 517
499 /* Linux can not store file creation time so ignore it */ 518 /* Linux can not store file creation time so ignore it */
500 if (pfindData->LastAccessTime) 519 if (pfindData->LastAccessTime)
501 inode->i_atime = cifs_NTtimeToUnix 520 inode->i_atime = cifs_NTtimeToUnix
502 (le64_to_cpu(pfindData->LastAccessTime)); 521 (le64_to_cpu(pfindData->LastAccessTime));
503 else /* do not need to use current_fs_time - time not stored */ 522 else /* do not need to use current_fs_time - time not stored */
504 inode->i_atime = CURRENT_TIME; 523 inode->i_atime = CURRENT_TIME;
505 inode->i_mtime = 524 inode->i_mtime =
506 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); 525 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
507 inode->i_ctime = 526 inode->i_ctime =
508 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); 527 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
509 cFYI(0, ("Attributes came in as 0x%x", attr)); 528 cFYI(DBG2, ("Attributes came in as 0x%x", attr));
510 if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { 529 if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
511 inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; 530 inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
512 inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; 531 inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
513 } 532 }
514 533
515 /* set default mode. will override for dirs below */ 534 /* get default inode mode */
516 if (atomic_read(&cifsInfo->inUse) == 0) 535 if (attr & ATTR_DIRECTORY)
517 /* new inode, can safely set these fields */ 536 default_mode = cifs_sb->mnt_dir_mode;
518 inode->i_mode = cifs_sb->mnt_file_mode; 537 else
519 else /* since we set the inode type below we need to mask off 538 default_mode = cifs_sb->mnt_file_mode;
520 to avoid strange results if type changes and both 539
521 get orred in */ 540 /* set permission bits */
541 if (atomic_read(&cifsInfo->inUse) == 0 ||
542 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
543 inode->i_mode = default_mode;
544 else {
545 /* just reenable write bits if !ATTR_READONLY */
546 if ((inode->i_mode & S_IWUGO) == 0 &&
547 (attr & ATTR_READONLY) == 0)
548 inode->i_mode |= (S_IWUGO & default_mode);
522 inode->i_mode &= ~S_IFMT; 549 inode->i_mode &= ~S_IFMT;
523/* if (attr & ATTR_REPARSE) */ 550 }
524 /* We no longer handle these as symlinks because we could not 551 /* clear write bits if ATTR_READONLY is set */
525 follow them due to the absolute path with drive letter */ 552 if (attr & ATTR_READONLY)
526 if (attr & ATTR_DIRECTORY) { 553 inode->i_mode &= ~S_IWUGO;
527 /* override default perms since we do not do byte range locking 554
528 on dirs */ 555 /* set inode type */
529 inode->i_mode = cifs_sb->mnt_dir_mode; 556 if ((attr & ATTR_SYSTEM) &&
530 inode->i_mode |= S_IFDIR; 557 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
531 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 558 /* no need to fix endianness on 0 */
532 (cifsInfo->cifsAttrs & ATTR_SYSTEM) && 559 if (pfindData->EndOfFile == 0)
533 /* No need to le64 convert size of zero */
534 (pfindData->EndOfFile == 0)) {
535 inode->i_mode = cifs_sb->mnt_file_mode;
536 inode->i_mode |= S_IFIFO; 560 inode->i_mode |= S_IFIFO;
537/* BB Finish for SFU style symlinks and devices */ 561 else if (decode_sfu_inode(inode,
538 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 562 le64_to_cpu(pfindData->EndOfFile),
539 (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { 563 full_path, cifs_sb, xid))
540 if (decode_sfu_inode(inode, 564 cFYI(1, ("unknown SFU file type\n"));
541 le64_to_cpu(pfindData->EndOfFile), 565 } else {
542 search_path, 566 if (attr & ATTR_DIRECTORY)
543 cifs_sb, xid)) 567 inode->i_mode |= S_IFDIR;
544 cFYI(1, ("Unrecognized sfu inode type")); 568 else
545
546 cFYI(1, ("sfu mode 0%o", inode->i_mode));
547 } else {
548 inode->i_mode |= S_IFREG; 569 inode->i_mode |= S_IFREG;
549 /* treat the dos attribute of read-only as read-only 570 }
550 mode e.g. 555 */
551 if (cifsInfo->cifsAttrs & ATTR_READONLY)
552 inode->i_mode &= ~(S_IWUGO);
553 else if ((inode->i_mode & S_IWUGO) == 0)
554 /* the ATTR_READONLY flag may have been */
555 /* changed on server -- set any w bits */
556 /* allowed by mnt_file_mode */
557 inode->i_mode |= (S_IWUGO &
558 cifs_sb->mnt_file_mode);
559 /* BB add code here -
560 validate if device or weird share or device type? */
561 }
562 571
563 spin_lock(&inode->i_lock); 572 spin_lock(&inode->i_lock);
564 if (is_size_safe_to_change(cifsInfo, 573 if (is_size_safe_to_change(cifsInfo,
565 le64_to_cpu(pfindData->EndOfFile))) { 574 le64_to_cpu(pfindData->EndOfFile))) {
566 /* can not safely shrink the file size here if the 575 /* can not safely shrink the file size here if the
567 client is writing to it due to potential races */ 576 client is writing to it due to potential races */
568 i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); 577 i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
569 578
570 /* 512 bytes (2**9) is the fake blocksize that must be 579 /* 512 bytes (2**9) is the fake blocksize that must be
571 used for this calculation */ 580 used for this calculation */
572 inode->i_blocks = (512 - 1 + le64_to_cpu( 581 inode->i_blocks = (512 - 1 + le64_to_cpu(
573 pfindData->AllocationSize)) >> 9; 582 pfindData->AllocationSize)) >> 9;
574 } 583 }
575 spin_unlock(&inode->i_lock); 584 spin_unlock(&inode->i_lock);
576 585
577 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); 586 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
578 587
579 /* BB fill in uid and gid here? with help from winbind? 588 /* BB fill in uid and gid here? with help from winbind?
580 or retrieve from NTFS stream extended attribute */ 589 or retrieve from NTFS stream extended attribute */
581#ifdef CONFIG_CIFS_EXPERIMENTAL 590#ifdef CONFIG_CIFS_EXPERIMENTAL
582 /* fill in 0777 bits from ACL */ 591 /* fill in 0777 bits from ACL */
583 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 592 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
584 cFYI(1, ("Getting mode bits from ACL")); 593 cFYI(1, ("Getting mode bits from ACL"));
585 acl_to_uid_mode(inode, search_path, pfid); 594 acl_to_uid_mode(inode, full_path, pfid);
586 } 595 }
587#endif 596#endif
588 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { 597 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
589 /* fill in remaining high mode bits e.g. SUID, VTX */ 598 /* fill in remaining high mode bits e.g. SUID, VTX */
590 get_sfu_mode(inode, search_path, cifs_sb, xid); 599 get_sfu_mode(inode, full_path, cifs_sb, xid);
591 } else if (atomic_read(&cifsInfo->inUse) == 0) { 600 } else if (atomic_read(&cifsInfo->inUse) == 0) {
592 inode->i_uid = cifs_sb->mnt_uid; 601 inode->i_uid = cifs_sb->mnt_uid;
593 inode->i_gid = cifs_sb->mnt_gid; 602 inode->i_gid = cifs_sb->mnt_gid;
594 /* set so we do not keep refreshing these fields with 603 /* set so we do not keep refreshing these fields with
595 bad data after user has changed them in memory */ 604 bad data after user has changed them in memory */
596 atomic_set(&cifsInfo->inUse, 1); 605 atomic_set(&cifsInfo->inUse, 1);
597 }
598
599 cifs_set_ops(inode, is_dfs_referral);
600 } 606 }
607
608 cifs_set_ops(inode, is_dfs_referral);
609
610
611
612
601cgii_exit: 613cgii_exit:
602 if (full_path != search_path)
603 kfree(full_path);
604 kfree(buf); 614 kfree(buf);
605 return rc; 615 return rc;
606} 616}
@@ -1005,8 +1015,11 @@ mkdir_get_info:
1005 CIFS_MOUNT_MAP_SPECIAL_CHR); 1015 CIFS_MOUNT_MAP_SPECIAL_CHR);
1006 } 1016 }
1007 if (direntry->d_inode) { 1017 if (direntry->d_inode) {
1008 direntry->d_inode->i_mode = mode; 1018 if (cifs_sb->mnt_cifs_flags &
1009 direntry->d_inode->i_mode |= S_IFDIR; 1019 CIFS_MOUNT_DYNPERM)
1020 direntry->d_inode->i_mode =
1021 (mode | S_IFDIR);
1022
1010 if (cifs_sb->mnt_cifs_flags & 1023 if (cifs_sb->mnt_cifs_flags &
1011 CIFS_MOUNT_SET_UID) { 1024 CIFS_MOUNT_SET_UID) {
1012 direntry->d_inode->i_uid = 1025 direntry->d_inode->i_uid =
@@ -1502,8 +1515,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1502 int oplock = 0; 1515 int oplock = 0;
1503 1516
1504 rc = SMBLegacyOpen(xid, pTcon, full_path, 1517 rc = SMBLegacyOpen(xid, pTcon, full_path,
1505 FILE_OPEN, 1518 FILE_OPEN, GENERIC_WRITE,
1506 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1507 CREATE_NOT_DIR, &netfid, &oplock, 1519 CREATE_NOT_DIR, &netfid, &oplock,
1508 NULL, cifs_sb->local_nls, 1520 NULL, cifs_sb->local_nls,
1509 cifs_sb->mnt_cifs_flags & 1521 cifs_sb->mnt_cifs_flags &
@@ -1534,13 +1546,26 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1534 } else 1546 } else
1535 goto cifs_setattr_exit; 1547 goto cifs_setattr_exit;
1536 } 1548 }
1537 if (attrs->ia_valid & ATTR_UID) { 1549
1538 cFYI(1, ("UID changed to %d", attrs->ia_uid)); 1550 /*
1539 uid = attrs->ia_uid; 1551 * Without unix extensions we can't send ownership changes to the
1540 } 1552 * server, so silently ignore them. This is consistent with how
1541 if (attrs->ia_valid & ATTR_GID) { 1553 * local DOS/Windows filesystems behave (VFAT, NTFS, etc). With
1542 cFYI(1, ("GID changed to %d", attrs->ia_gid)); 1554 * CIFSACL support + proper Windows to Unix idmapping, we may be
1543 gid = attrs->ia_gid; 1555 * able to support this in the future.
1556 */
1557 if (!pTcon->unix_ext &&
1558 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
1559 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
1560 } else {
1561 if (attrs->ia_valid & ATTR_UID) {
1562 cFYI(1, ("UID changed to %d", attrs->ia_uid));
1563 uid = attrs->ia_uid;
1564 }
1565 if (attrs->ia_valid & ATTR_GID) {
1566 cFYI(1, ("GID changed to %d", attrs->ia_gid));
1567 gid = attrs->ia_gid;
1568 }
1544 } 1569 }
1545 1570
1546 time_buf.Attributes = 0; 1571 time_buf.Attributes = 0;
@@ -1550,7 +1575,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1550 attrs->ia_valid &= ~ATTR_MODE; 1575 attrs->ia_valid &= ~ATTR_MODE;
1551 1576
1552 if (attrs->ia_valid & ATTR_MODE) { 1577 if (attrs->ia_valid & ATTR_MODE) {
1553 cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); 1578 cFYI(1, ("Mode changed to 0%o", attrs->ia_mode));
1554 mode = attrs->ia_mode; 1579 mode = attrs->ia_mode;
1555 } 1580 }
1556 1581
@@ -1565,18 +1590,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1565#ifdef CONFIG_CIFS_EXPERIMENTAL 1590#ifdef CONFIG_CIFS_EXPERIMENTAL
1566 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) 1591 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
1567 rc = mode_to_acl(inode, full_path, mode); 1592 rc = mode_to_acl(inode, full_path, mode);
1568 else if ((mode & S_IWUGO) == 0) { 1593 else
1569#else
1570 if ((mode & S_IWUGO) == 0) {
1571#endif 1594#endif
1572 /* not writeable */ 1595 if (((mode & S_IWUGO) == 0) &&
1573 if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) { 1596 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
1574 set_dosattr = true; 1597 set_dosattr = true;
1575 time_buf.Attributes = 1598 time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs |
1576 cpu_to_le32(cifsInode->cifsAttrs | 1599 ATTR_READONLY);
1577 ATTR_READONLY); 1600 /* fix up mode if we're not using dynperm */
1578 } 1601 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
1579 } else if (cifsInode->cifsAttrs & ATTR_READONLY) { 1602 attrs->ia_mode = inode->i_mode & ~S_IWUGO;
1603 } else if ((mode & S_IWUGO) &&
1604 (cifsInode->cifsAttrs & ATTR_READONLY)) {
1580 /* If file is readonly on server, we would 1605 /* If file is readonly on server, we would
1581 not be able to write to it - so if any write 1606 not be able to write to it - so if any write
1582 bit is enabled for user or group or other we 1607 bit is enabled for user or group or other we
@@ -1587,6 +1612,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1587 /* Windows ignores set to zero */ 1612 /* Windows ignores set to zero */
1588 if (time_buf.Attributes == 0) 1613 if (time_buf.Attributes == 0)
1589 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL); 1614 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
1615
1616 /* reset local inode permissions to normal */
1617 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
1618 attrs->ia_mode &= ~(S_IALLUGO);
1619 if (S_ISDIR(inode->i_mode))
1620 attrs->ia_mode |=
1621 cifs_sb->mnt_dir_mode;
1622 else
1623 attrs->ia_mode |=
1624 cifs_sb->mnt_file_mode;
1625 }
1626 } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
1627 /* ignore mode change - ATTR_READONLY hasn't changed */
1628 attrs->ia_valid &= ~ATTR_MODE;
1590 } 1629 }
1591 } 1630 }
1592 1631