]> err.no Git - linux-2.6/blobdiff - fs/cifs/dir.c
[CIFS] Fix setattr of mode only (e.g. in some chmod cases) to Windows
[linux-2.6] / fs / cifs / dir.c
index 5311c50734b0a2056f28cebeda86d9fa5148831e..16b21522e8fe1bbd06a97a7da2297e38cc8056d3 100644 (file)
@@ -43,11 +43,12 @@ renew_parental_timestamps(struct dentry *direntry)
 
 /* Note: caller must free return buffer */
 char *
-build_path_from_dentry(struct dentry *direntry, const struct cifs_sb_info *cifs_sb)
+build_path_from_dentry(struct dentry *direntry)
 {
        struct dentry *temp;
        int namelen = 0;
        char *full_path;
+       char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
 
        if(direntry == NULL)
                return NULL;  /* not much we can do if dentry is freed and
@@ -74,7 +75,7 @@ cifs_bp_rename_retry:
                if (namelen < 0) {
                        break;
                } else {
-                       full_path[namelen] = CIFS_DIR_SEP(cifs_sb);
+                       full_path[namelen] = dirsep;
                        strncpy(full_path + namelen + 1, temp->d_name.name,
                                temp->d_name.len);
                        cFYI(0, (" name: %s ", full_path + namelen));
@@ -138,31 +139,30 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        pTcon = cifs_sb->tcon;
 
        down(&direntry->d_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry, cifs_sb);
+       full_path = build_path_from_dentry(direntry);
        up(&direntry->d_sb->s_vfs_rename_sem);
        if(full_path == NULL) {
                FreeXid(xid);
                return -ENOMEM;
        }
 
-       if(nd) {
-               if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY)
-                       desiredAccess = GENERIC_READ;
-               else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) {
-                       desiredAccess = GENERIC_WRITE;
-                       write_only = TRUE;
-               } else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) {
-                       /* GENERIC_ALL is too much permission to request */
-                       /* can cause unnecessary access denied on create */
-                       /* desiredAccess = GENERIC_ALL; */
-                       desiredAccess = GENERIC_READ | GENERIC_WRITE;
+       if(nd && (nd->flags & LOOKUP_OPEN)) {
+               int oflags = nd->intent.open.flags;
+
+               desiredAccess = 0;
+               if (oflags & FMODE_READ)
+                       desiredAccess |= GENERIC_READ;
+               if (oflags & FMODE_WRITE) {
+                       desiredAccess |= GENERIC_WRITE;
+                       if (!(oflags & FMODE_READ))
+                               write_only = TRUE;
                }
 
-               if((nd->intent.open.flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+               if((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
                        disposition = FILE_CREATE;
-               else if((nd->intent.open.flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
+               else if((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
                        disposition = FILE_OVERWRITE_IF;
-               else if((nd->intent.open.flags & O_CREAT) == O_CREAT)
+               else if((oflags & O_CREAT) == O_CREAT)
                        disposition = FILE_OPEN_IF;
                else {
                        cFYI(1,("Create flag not set in create function"));
@@ -184,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                         desiredAccess, CREATE_NOT_DIR,
                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if(rc == -EIO) {
+               /* old server, retry the open legacy style */
+               rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
+                       desiredAccess, CREATE_NOT_DIR,
+                       &fileHandle, &oplock, buf, cifs_sb->local_nls,
+                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       } 
        if (rc) {
                cFYI(1, ("cifs_create returned 0x%x ", rc));
        } else {
@@ -285,7 +292,8 @@ cifs_create_out:
        return rc;
 }
 
-int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t device_number) 
+int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, 
+               dev_t device_number) 
 {
        int rc = -EPERM;
        int xid;
@@ -303,7 +311,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
        pTcon = cifs_sb->tcon;
 
        down(&direntry->d_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry, cifs_sb);
+       full_path = build_path_from_dentry(direntry);
        up(&direntry->d_sb->s_vfs_rename_sem);
        if(full_path == NULL)
                rc = -ENOMEM;
@@ -361,7 +369,34 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
 
                        if(!rc) {
                                /* BB Do not bother to decode buf since no
-                                  local inode yet to put timestamps in */
+                                  local inode yet to put timestamps in,
+                                  but we can reuse it safely */
+                               int bytes_written;
+                               struct win_dev *pdev;
+                               pdev = (struct win_dev *)buf;
+                               if(S_ISCHR(mode)) {
+                                       memcpy(pdev->type, "IntxCHR", 8);
+                                       pdev->major =
+                                             cpu_to_le64(MAJOR(device_number));
+                                       pdev->minor = 
+                                             cpu_to_le64(MINOR(device_number));
+                                       rc = CIFSSMBWrite(xid, pTcon,
+                                               fileHandle,
+                                               sizeof(struct win_dev),
+                                               0, &bytes_written, (char *)pdev,
+                                               NULL, 0);
+                               } else if(S_ISBLK(mode)) {
+                                       memcpy(pdev->type, "IntxBLK", 8);
+                                       pdev->major =
+                                             cpu_to_le64(MAJOR(device_number));
+                                       pdev->minor =
+                                             cpu_to_le64(MINOR(device_number));
+                                       rc = CIFSSMBWrite(xid, pTcon,
+                                               fileHandle,
+                                               sizeof(struct win_dev),
+                                               0, &bytes_written, (char *)pdev,
+                                               NULL, 0);
+                               } /* else if(S_ISFIFO */
                                CIFSSMBClose(xid, pTcon, fileHandle);
                                d_drop(direntry);
                        }
@@ -402,7 +437,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
        /* can not grab the rename sem here since it would
        deadlock in the cases (beginning of sys_rename itself)
        in which we already have the sb rename sem */
-       full_path = build_path_from_dentry(direntry, cifs_sb);
+       full_path = build_path_from_dentry(direntry);
        if(full_path == NULL) {
                FreeXid(xid);
                return ERR_PTR(-ENOMEM);