4 * Copyright (C) International Business Machines Corp., 2002,2003
5 * Author(s): Steve French (sfrench@us.ibm.com)
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <linux/buffer_head.h>
23 #include <linux/stat.h>
24 #include <linux/pagemap.h>
25 #include <asm/div64.h>
29 #include "cifsproto.h"
30 #include "cifs_debug.h"
31 #include "cifs_fs_sb.h"
34 cifs_get_inode_info_unix(struct inode **pinode,
35 const unsigned char *search_path,
36 struct super_block *sb)
40 FILE_UNIX_BASIC_INFO findData;
41 struct cifsTconInfo *pTcon;
43 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
46 /* BB add caching check so we do not go to server to overwrite inode info to cached file
47 where the local file sizes are correct and the server info is stale BB */
51 pTcon = cifs_sb->tcon;
52 cFYI(1, (" Getting info on %s ", search_path));
53 /* we could have done a find first instead but this returns more info */
54 rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
56 /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
63 strnlen(search_path, MAX_PATHCONF) + 1,
65 if (tmp_path == NULL) {
69 /* have to skip first of the double backslash of UNC name */
70 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
71 strncat(tmp_path, search_path, MAX_PATHCONF);
72 rc = connect_to_dfs_path(xid, pTcon->ses,
73 /* treename + */ tmp_path,
77 /* BB fix up inode etc. */
84 struct cifsInodeInfo *cifsInfo;
87 if (*pinode == NULL) {
88 *pinode = new_inode(sb);
92 cifsInfo = CIFS_I(inode);
94 cFYI(1, (" Old time %ld ", cifsInfo->time));
95 cifsInfo->time = jiffies;
96 cFYI(1, (" New time %ld ", cifsInfo->time));
97 atomic_set(&cifsInfo->inUse,1); /* ok to set on every refresh of inode */
100 cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
102 cifs_NTtimeToUnix(le64_to_cpu
103 (findData.LastModificationTime));
105 cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
106 inode->i_mode = le64_to_cpu(findData.Permissions);
107 findData.Type = le32_to_cpu(findData.Type);
108 if (findData.Type == UNIX_FILE) {
109 inode->i_mode |= S_IFREG;
110 } else if (findData.Type == UNIX_SYMLINK) {
111 inode->i_mode |= S_IFLNK;
112 } else if (findData.Type == UNIX_DIR) {
113 inode->i_mode |= S_IFDIR;
114 } else if (findData.Type == UNIX_CHARDEV) {
115 inode->i_mode |= S_IFCHR;
116 } else if (findData.Type == UNIX_BLOCKDEV) {
117 inode->i_mode |= S_IFBLK;
118 } else if (findData.Type == UNIX_FIFO) {
119 inode->i_mode |= S_IFIFO;
120 } else if (findData.Type == UNIX_SOCKET) {
121 inode->i_mode |= S_IFSOCK;
123 inode->i_uid = le64_to_cpu(findData.Uid);
124 inode->i_gid = le64_to_cpu(findData.Gid);
125 inode->i_nlink = le64_to_cpu(findData.Nlinks);
126 findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes);
127 findData.EndOfFile = le64_to_cpu(findData.EndOfFile);
128 i_size_write(inode,findData.EndOfFile);
129 /* blksize needs to be multiple of two. So safer to default to blksize
130 and blkbits set in superblock so 2**blkbits and blksize will match */
131 /* inode->i_blksize =
132 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
134 (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;
136 if (findData.NumOfBytes < findData.EndOfFile)
137 cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
139 ("Size %ld and blocks %ld ",
140 (unsigned long) inode->i_size, inode->i_blocks));
141 if (S_ISREG(inode->i_mode)) {
142 cFYI(1, (" File inode "));
143 inode->i_op = &cifs_file_inode_ops;
144 inode->i_fop = &cifs_file_ops;
145 inode->i_data.a_ops = &cifs_addr_ops;
146 } else if (S_ISDIR(inode->i_mode)) {
147 cFYI(1, (" Directory inode"));
148 inode->i_op = &cifs_dir_inode_ops;
149 inode->i_fop = &cifs_dir_ops;
150 } else if (S_ISLNK(inode->i_mode)) {
151 cFYI(1, (" Symbolic Link inode "));
152 inode->i_op = &cifs_symlink_inode_ops;
153 /* tmp_inode->i_fop = *//* do not need to set to anything */
155 cFYI(1, (" Init special inode "));
156 init_special_inode(inode, inode->i_mode,
165 cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
166 FILE_ALL_INFO * pfindData, struct super_block *sb)
170 struct cifsTconInfo *pTcon;
172 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
178 pTcon = cifs_sb->tcon;
179 cFYI(1,("Getting info on %s ", search_path));
181 if((pfindData == NULL) && (*pinode != NULL)) {
182 if(CIFS_I(*pinode)->clientCanCacheRead) {
183 cFYI(1,("No need to revalidate inode sizes on cached file "));
189 /* if file info not passed in then get it from server */
190 if(pfindData == NULL) {
191 buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
192 pfindData = (FILE_ALL_INFO *)buf;
193 /* could do find first instead but this returns more info */
194 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
197 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
199 if (rc == -EREMOTE) {
204 strnlen(search_path, MAX_PATHCONF) + 1,
206 if (tmp_path == NULL) {
213 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
214 strncat(tmp_path, search_path, MAX_PATHCONF);
215 rc = connect_to_dfs_path(xid, pTcon->ses,
216 /* treename + */ tmp_path,
219 /* BB fix up inode etc. */
227 struct cifsInodeInfo *cifsInfo;
230 if (*pinode == NULL) {
231 *pinode = new_inode(sb);
235 cifsInfo = CIFS_I(inode);
236 pfindData->Attributes = le32_to_cpu(pfindData->Attributes);
237 cifsInfo->cifsAttrs = pfindData->Attributes;
238 cFYI(1, (" Old time %ld ", cifsInfo->time));
239 cifsInfo->time = jiffies;
240 cFYI(1, (" New time %ld ", cifsInfo->time));
242 /* blksize needs to be multiple of two. So safer to default to blksize
243 and blkbits set in superblock so 2**blkbits and blksize will match */
244 /* inode->i_blksize =
245 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
247 /* Linux can not store file creation time unfortunately so we ignore it */
249 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
251 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
253 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
255 (" Attributes came in as 0x%x ", pfindData->Attributes));
257 /* set default mode. will override for dirs below */
258 if(atomic_read(&cifsInfo->inUse) == 0)
259 /* new inode, can safely set these fields */
260 inode->i_mode = cifs_sb->mnt_file_mode;
262 if (pfindData->Attributes & ATTR_REPARSE) {
263 /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
264 inode->i_mode |= S_IFLNK;
265 } else if (pfindData->Attributes & ATTR_DIRECTORY) {
266 /* override default perms since we do not do byte range locking on dirs */
267 inode->i_mode = cifs_sb->mnt_dir_mode;
268 inode->i_mode |= S_IFDIR;
270 inode->i_mode |= S_IFREG;
271 /* treat the dos attribute of read-only as read-only mode e.g. 555 */
272 if(cifsInfo->cifsAttrs & ATTR_READONLY)
273 inode->i_mode &= ~(S_IWUGO);
274 /* BB add code here - validate if device or weird share or device type? */
276 i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
277 pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
279 (inode->i_blksize - 1 + pfindData->AllocationSize) >> inode->i_blkbits;
281 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
283 /* BB fill in uid and gid here? with help from winbind?
284 or retrieve from NTFS stream extended attribute */
285 if(atomic_read(&cifsInfo->inUse) == 0) {
286 inode->i_uid = cifs_sb->mnt_uid;
287 inode->i_gid = cifs_sb->mnt_gid;
288 /* set so we do not keep refreshing these fields with
289 bad data after user has changed them in memory */
290 atomic_set(&cifsInfo->inUse,1);
293 if (S_ISREG(inode->i_mode)) {
294 cFYI(1, (" File inode "));
295 inode->i_op = &cifs_file_inode_ops;
296 inode->i_fop = &cifs_file_ops;
297 inode->i_data.a_ops = &cifs_addr_ops;
298 } else if (S_ISDIR(inode->i_mode)) {
299 cFYI(1, (" Directory inode "));
300 inode->i_op = &cifs_dir_inode_ops;
301 inode->i_fop = &cifs_dir_ops;
302 } else if (S_ISLNK(inode->i_mode)) {
303 cFYI(1, (" Symbolic Link inode "));
304 inode->i_op = &cifs_symlink_inode_ops;
306 init_special_inode(inode, inode->i_mode,
317 cifs_read_inode(struct inode *inode)
318 { /* gets root inode */
320 struct cifs_sb_info *cifs_sb;
322 cifs_sb = CIFS_SB(inode->i_sb);
324 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
325 cifs_get_inode_info_unix(&inode, "", inode->i_sb);
327 cifs_get_inode_info(&inode, "", NULL, inode->i_sb);
331 cifs_unlink(struct inode *inode, struct dentry *direntry)
335 struct cifs_sb_info *cifs_sb;
336 struct cifsTconInfo *pTcon;
337 char *full_path = NULL;
338 struct cifsInodeInfo *cifsInode;
339 FILE_BASIC_INFO * pinfo_buf;
341 cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
345 cifs_sb = CIFS_SB(inode->i_sb);
346 pTcon = cifs_sb->tcon;
348 full_path = build_path_from_dentry(direntry);
350 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
353 direntry->d_inode->i_nlink--;
354 } else if (rc == -ENOENT) {
356 } else if (rc == -ETXTBSY) {
360 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
361 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
362 &netfid, &oplock, NULL, cifs_sb->local_nls);
364 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
365 NULL, cifs_sb->local_nls);
366 CIFSSMBClose(xid, pTcon, netfid);
367 direntry->d_inode->i_nlink--;
369 } else if (rc == -EACCES) {
370 /* try only if r/o attribute set in local lookup data? */
371 pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL);
373 memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO));
374 /* ATTRS set to normal clears r/o bit */
375 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
376 rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf,
381 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
383 direntry->d_inode->i_nlink--;
384 } else if (rc == -ETXTBSY) {
388 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
389 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
390 &netfid, &oplock, NULL, cifs_sb->local_nls);
392 CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls);
393 CIFSSMBClose(xid, pTcon, netfid);
394 direntry->d_inode->i_nlink--;
396 /* BB if rc = -ETXTBUSY goto the rename logic BB */
400 cifsInode = CIFS_I(direntry->d_inode);
401 cifsInode->time = 0; /* will force revalidate to get info when needed */
402 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
404 cifsInode = CIFS_I(inode);
405 cifsInode->time = 0; /* force revalidate of dir as well */
414 cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
418 struct cifs_sb_info *cifs_sb;
419 struct cifsTconInfo *pTcon;
420 char *full_path = NULL;
421 struct inode *newinode = NULL;
423 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
427 cifs_sb = CIFS_SB(inode->i_sb);
428 pTcon = cifs_sb->tcon;
430 full_path = build_path_from_dentry(direntry);
431 /* BB add setting the equivalent of mode via CreateX w/ACLs */
432 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
434 cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
438 if (pTcon->ses->capabilities & CAP_UNIX)
439 rc = cifs_get_inode_info_unix(&newinode, full_path,
442 rc = cifs_get_inode_info(&newinode, full_path,NULL,
445 direntry->d_op = &cifs_dentry_ops;
446 d_instantiate(direntry, newinode);
447 if(direntry->d_inode)
448 direntry->d_inode->i_nlink = 2;
449 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
450 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
455 else { /* BB to be implemented via Windows secrty descriptors*/
456 /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
467 cifs_rmdir(struct inode *inode, struct dentry *direntry)
471 struct cifs_sb_info *cifs_sb;
472 struct cifsTconInfo *pTcon;
473 char *full_path = NULL;
474 struct cifsInodeInfo *cifsInode;
476 cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
480 cifs_sb = CIFS_SB(inode->i_sb);
481 pTcon = cifs_sb->tcon;
483 full_path = build_path_from_dentry(direntry);
485 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
489 i_size_write(direntry->d_inode,0);
490 direntry->d_inode->i_nlink = 0;
493 cifsInode = CIFS_I(direntry->d_inode);
494 cifsInode->time = 0; /* force revalidate to go get info when needed */
495 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
505 cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
506 struct inode *target_inode, struct dentry *target_direntry)
510 struct cifs_sb_info *cifs_sb_source;
511 struct cifs_sb_info *cifs_sb_target;
512 struct cifsTconInfo *pTcon;
518 cifs_sb_target = CIFS_SB(target_inode->i_sb);
519 cifs_sb_source = CIFS_SB(source_inode->i_sb);
520 pTcon = cifs_sb_source->tcon;
522 if (pTcon != cifs_sb_target->tcon) {
524 return -EXDEV; /* BB actually could be allowed if same server, but
525 different share. Might eventually add support for this */
528 fromName = build_path_from_dentry(source_direntry);
529 toName = build_path_from_dentry(target_direntry);
531 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
532 cifs_sb_source->local_nls);
534 cifs_unlink(target_inode, target_direntry);
535 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
536 cifs_sb_source->local_nls);
539 if((rc == -EIO)||(rc == -EEXIST)) {
543 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
545 &netfid, &oplock, NULL, cifs_sb_source->local_nls);
547 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
548 toName, cifs_sb_source->local_nls);
549 CIFSSMBClose(xid, pTcon, netfid);
562 cifs_revalidate(struct dentry *direntry)
567 struct cifs_sb_info *cifs_sb;
568 struct cifsInodeInfo *cifsInode;
570 struct timespec local_mtime;
571 int invalidate_inode = FALSE;
573 if(direntry->d_inode == NULL)
576 cifsInode = CIFS_I(direntry->d_inode);
578 if(cifsInode == NULL)
581 /* no sense revalidating inode info on file that no one can write */
582 if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
587 cifs_sb = CIFS_SB(direntry->d_sb);
589 full_path = build_path_from_dentry(direntry);
591 ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
592 full_path, direntry->d_inode,
593 direntry->d_inode->i_count.counter, direntry,
594 direntry->d_time, jiffies));
596 if (cifsInode->time == 0){
597 /* was set to zero previously to force revalidate */
598 } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
599 if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
600 (direntry->d_inode->i_nlink == 1)) {
606 cFYI(1,("Have to revalidate file due to hardlinks"));
610 /* save mtime and size */
611 local_mtime = direntry->d_inode->i_mtime;
612 local_size = direntry->d_inode->i_size;
614 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
615 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
618 cFYI(1,("error on getting revalidate info %d",rc));
620 rc = 0; */ /* BB should we cache info on certain errors? */
623 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
626 cFYI(1,("error on getting revalidate info %d",rc));
628 rc = 0; */ /* BB should we cache info on certain errors? */
631 /* should we remap certain errors, access denied?, to zero */
633 /* if not oplocked, we invalidate inode pages if mtime
634 or file size had changed on server */
636 if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
637 (local_size == direntry->d_inode->i_size)) {
638 cFYI(1,("cifs_revalidate - inode unchanged"));
640 /* file may have changed on server */
641 if(cifsInode->clientCanCacheRead) {
642 /* no need to invalidate inode pages since we were
643 the only ones who could have modified the file and
644 the server copy is staler than ours */
646 invalidate_inode = TRUE;
651 /* need to write out dirty pages here */
652 down(&direntry->d_inode->i_sem);
653 if(direntry->d_inode->i_mapping) {
654 /* do we need to lock inode until after invalidate completes below? */
655 filemap_fdatawrite(direntry->d_inode->i_mapping);
657 if(invalidate_inode) {
658 filemap_fdatawait(direntry->d_inode->i_mapping);
659 /* may eventually have to do this for open files too */
660 if(list_empty(&(cifsInode->openFileList))) {
661 /* Has changed on server - flush read ahead pages */
662 cFYI(1,("Invalidating read ahead data on closed file"));
663 invalidate_remote_inode(direntry->d_inode);
668 up(&direntry->d_inode->i_sem);
677 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
679 int err = cifs_revalidate(dentry);
681 generic_fillattr(dentry->d_inode, stat);
685 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
687 pgoff_t index = from >> PAGE_CACHE_SHIFT;
688 unsigned offset = from & (PAGE_CACHE_SIZE-1);
693 page = grab_cache_page(mapping, index);
697 kaddr = kmap_atomic(page, KM_USER0);
698 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
699 flush_dcache_page(page);
700 kunmap_atomic(kaddr, KM_USER0);
702 page_cache_release(page);
707 cifs_setattr(struct dentry *direntry, struct iattr *attrs)
710 struct cifs_sb_info *cifs_sb;
711 struct cifsTconInfo *pTcon;
712 char *full_path = NULL;
715 struct cifsFileInfo *open_file = NULL;
716 FILE_BASIC_INFO time_buf;
717 int set_time = FALSE;
718 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
719 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
720 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
721 struct cifsInodeInfo *cifsInode;
722 struct list_head * tmp;
727 (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
728 direntry->d_name.name, attrs->ia_valid));
729 cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
730 pTcon = cifs_sb->tcon;
732 full_path = build_path_from_dentry(direntry);
733 cifsInode = CIFS_I(direntry->d_inode);
735 /* BB check if we need to refresh inode from server now ? BB */
737 /* need to flush data before changing file size on server */
738 filemap_fdatawrite(direntry->d_inode->i_mapping);
739 filemap_fdatawait(direntry->d_inode->i_mapping);
741 if (attrs->ia_valid & ATTR_SIZE) {
742 read_lock(&GlobalSMBSeslock);
743 /* To avoid spurious oplock breaks from server, in the case
744 of inodes that we already have open, avoid doing path
745 based setting of file size if we can do it by handle.
746 This keeps our caching token (oplock) and avoids
747 timeouts when the local oplock break takes longer to flush
748 writebehind data than the SMB timeout for the SetPathInfo
749 request would allow */
750 list_for_each(tmp, &cifsInode->openFileList) {
751 open_file = list_entry(tmp,struct cifsFileInfo, flist);
752 /* We check if file is open for writing first */
753 if((open_file->pfile) &&
754 ((open_file->pfile->f_flags & O_RDWR) ||
755 (open_file->pfile->f_flags & O_WRONLY))) {
756 if(open_file->invalidHandle == FALSE) {
757 /* we found a valid, writeable network file
758 handle to use to try to set the file size */
759 __u16 nfid = open_file->netfid;
760 __u32 npid = open_file->pid;
761 read_unlock(&GlobalSMBSeslock);
763 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
765 cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
766 /* Do not need reopen and retry on EAGAIN since we will
767 retry by pathname below */
769 break; /* now that we found one valid file handle no
770 sense continuing to loop trying others */
775 read_unlock(&GlobalSMBSeslock);
780 /* Set file size by pathname rather than by handle either
781 because no valid, writeable file handle for it was found or
782 because there was an error setting it by handle */
783 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
785 cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
788 /* Server is ok setting allocation size implicitly - no need to call: */
789 /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/
792 rc = vmtruncate(direntry->d_inode, attrs->ia_size);
793 cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size);
796 if (attrs->ia_valid & ATTR_UID) {
797 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
799 /* entry->uid = cpu_to_le16(attr->ia_uid); */
801 if (attrs->ia_valid & ATTR_GID) {
802 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
804 /* entry->gid = cpu_to_le16(attr->ia_gid); */
807 time_buf.Attributes = 0;
808 if (attrs->ia_valid & ATTR_MODE) {
809 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
810 mode = attrs->ia_mode;
811 /* entry->mode = cpu_to_le16(attr->ia_mode); */
814 if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
815 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
816 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
817 0 /* dev_t */, cifs_sb->local_nls);
818 else if (attrs->ia_valid & ATTR_MODE) {
819 if((mode & S_IWUGO) == 0) /* not writeable */ {
820 if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
821 time_buf.Attributes =
822 cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
823 } else if((mode & S_IWUGO) == S_IWUGO) {
824 if(cifsInode->cifsAttrs & ATTR_READONLY)
825 time_buf.Attributes =
826 cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
828 /* BB to be implemented - via Windows security descriptors or streams */
829 /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
832 if (attrs->ia_valid & ATTR_ATIME) {
834 time_buf.LastAccessTime =
835 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
837 time_buf.LastAccessTime = 0;
839 if (attrs->ia_valid & ATTR_MTIME) {
841 time_buf.LastWriteTime =
842 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
844 time_buf.LastWriteTime = 0;
846 if (attrs->ia_valid & ATTR_CTIME) {
848 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably do not need */
849 time_buf.ChangeTime =
850 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
852 time_buf.ChangeTime = 0;
854 if (set_time | time_buf.Attributes) {
855 /* BB what if setting one attribute fails
856 (such as size) but time setting works */
857 time_buf.CreationTime = 0; /* do not change */
858 /* In the future we should experiment - try setting timestamps
859 via Handle (SetFileInfo) instead of by path */
860 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
864 /* do not need local check to inode_check_ok since the server does that */
865 inode_setattr(direntry->d_inode, attrs);
873 cifs_delete_inode(struct inode *inode)
875 cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
876 /* may have to add back in if and when safe distributed caching of
877 directories added e.g. via FindNotify */