Commit e30dcf3a authored by Steve French's avatar Steve French
Browse files

[CIFS] Add support for legacy servers part eight. Write fixes for Windows


ME, and do not set ctime unless explicitly requested with atime and/or
mtime (it gets thrown away by most servers anyway as there is no way to set
this via posix).

Signed-off-by: default avatarSteve French <(sfrench@us.ibm.com)>
parent 3e87d803
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@ Version 1.37
------------
Fix readdir caching when unlink removes file in current search buffer,
and this is followed by a rewind search to just before the deleted entry.
Do not attempt to set ctime unless atime and/or mtime change requested
(most servers throw it away anyway).

Version 1.36
------------
+1 −1
Original line number Diff line number Diff line
@@ -256,7 +256,7 @@ cifs_alloc_inode(struct super_block *sb)
	cifs_inode->clientCanCacheAll = FALSE;
	cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE;
	cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */

	cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;
	INIT_LIST_HEAD(&cifs_inode->openFileList);
	return &cifs_inode->vfs_inode;
}
+9 −6
Original line number Diff line number Diff line
@@ -1080,20 +1080,23 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
			cifs_buf_release(pSMB);
			return -EFAULT;
		}
	} else {
	} else if (count != 0) {
		/* No buffer */
		cifs_buf_release(pSMB);
		return -EINVAL;
	} /* else setting file size with write of zero bytes */
	if(wct == 14)
		byte_count = bytes_sent + 1; /* pad */
	else /* wct == 12 */ {
		byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
	}

	byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
	pSMB->hdr.smb_buf_length += bytes_sent+1;
	pSMB->hdr.smb_buf_length += byte_count;

	if(wct == 14)
		pSMB->ByteCount = cpu_to_le16(byte_count);
	else { /* old style write has byte count 4 bytes earlier */
	else { /* old style write has byte count 4 bytes earlier so 4 bytes pad  */
		struct smb_com_writex_req * pSMBW = 
			(struct smb_com_writex_req *)pSMB;
		pSMBW->ByteCount = cpu_to_le16(byte_count);
+54 −24
Original line number Diff line number Diff line
@@ -1030,14 +1030,15 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
					/* now that we found one valid file
					   handle no sense continuing to loop
					   trying others, so break here */
					/* if(rc == -EINVAL) {
					if(rc == -EINVAL) {
						int bytes_written;
						rc = CIFSSMBWrite(xid, pTcon,
							nfid, 0,
							attrs->ia_size, 
							&bytes_written,
							NULL, NULL, long_op);
					} */
							&bytes_written, NULL,
							NULL, 1 /* 45 sec */);
						cFYI(1,("wrt seteof rc %d",rc));
					}
					break;
				}
			}
@@ -1056,13 +1057,29 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
					   cifs_sb->mnt_cifs_flags &
						CIFS_MOUNT_MAP_SPECIAL_CHR);
			cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
			/* if(rc == -EINVAL)
				old_style_set_eof_via_write(xid, pTcon, 
						full_path, 
						attrs->ia_size,
						cifs_sb->local_nls,
			if(rc == -EINVAL) {
				__u16 netfid;
				int oplock = FALSE;

				rc = SMBLegacyOpen(xid, pTcon, full_path,
					FILE_OPEN,
					SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
					CREATE_NOT_DIR, &netfid, &oplock,
					NULL, cifs_sb->local_nls,
					cifs_sb->mnt_cifs_flags &
						  CIFS_MOUNT_MAP_SPECIAL_CHR);*/
						CIFS_MOUNT_MAP_SPECIAL_CHR);
				if (rc==0) {
					int bytes_written;
					rc = CIFSSMBWrite(xid, pTcon,
							netfid, 0,
							attrs->ia_size,
							&bytes_written, NULL,
							NULL, 1 /* 45 sec */);
					cFYI(1,("wrt seteof rc %d",rc));
					CIFSSMBClose(xid, pTcon, netfid);
				}

			}
		}

		/* Server is ok setting allocation size implicitly - no need
@@ -1075,24 +1092,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
			rc = vmtruncate(direntry->d_inode, attrs->ia_size);
			cifs_truncate_page(direntry->d_inode->i_mapping,
					   direntry->d_inode->i_size);
		}
		} else 
			goto cifs_setattr_exit;
	}
	if (attrs->ia_valid & ATTR_UID) {
		cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
		cFYI(1, ("UID changed to %d", attrs->ia_uid));
		uid = attrs->ia_uid;
		/* entry->uid = cpu_to_le16(attr->ia_uid); */
	}
	if (attrs->ia_valid & ATTR_GID) {
		cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
		cFYI(1, ("GID changed to %d", attrs->ia_gid));
		gid = attrs->ia_gid;
		/* entry->gid = cpu_to_le16(attr->ia_gid); */
	}

	time_buf.Attributes = 0;
	if (attrs->ia_valid & ATTR_MODE) {
		cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
		cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode));
		mode = attrs->ia_mode;
		/* entry->mode = cpu_to_le16(attr->ia_mode); */
	}

	if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
@@ -1132,18 +1147,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
	} else
		time_buf.LastWriteTime = 0;
	/* Do not set ctime explicitly unless other time
	   stamps are changed explicitly (i.e. by utime()
	   since we would then have a mix of client and
	   server times */
	   
	if (attrs->ia_valid & ATTR_CTIME) {
	if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
		set_time = TRUE;
		cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */
		/* Although Samba throws this field away
		it may be useful to Windows - but we do
		not want to set ctime unless some other
		timestamp is changing */
		cFYI(1, ("CIFS - CTIME changed "));
		time_buf.ChangeTime =
		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
	} else
		time_buf.ChangeTime = 0;

	if (set_time || time_buf.Attributes) {
		/* BB what if setting one attribute fails (such as size) but
		   time setting works? */
		time_buf.CreationTime = 0;	/* do not change */
		/* In the future we should experiment - try setting timestamps
		   via Handle (SetFileInfo) instead of by path */
@@ -1182,12 +1203,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
        	        		&time_buf, cifs_sb->local_nls); */
			}
		}
		/* Even if error on time set, no sense failing the call if
		the server would set the time to a reasonable value anyway,
		and this check ensures that we are not being called from
		sys_utimes in which case we ought to fail the call back to
		the user when the server rejects the call */
		if((rc) && (attrs->ia_valid &&
			 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
			rc = 0;
	}

	/* do not need local check to inode_check_ok since the server does
	   that */
	if (!rc)
		rc = inode_setattr(direntry->d_inode, attrs);
cifs_setattr_exit:
	kfree(full_path);
	FreeXid(xid);
	return rc;