]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
HGFS: Fix Linux client to work with Perforce versioning
authorVMware, Inc <>
Wed, 18 Sep 2013 03:13:28 +0000 (20:13 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 23 Sep 2013 05:01:52 +0000 (22:01 -0700)
The problem is that perforce client uses rename operation upon a temp
file which has read-only attributes. The operation then fails with
permission denied.

The fix removes the read only attribute and retries the rename operation
again as per the delete operation. This occurs on Windows HGFS servers
as the target of the rename operation to be replaced has the read only
attribute set. The prevents a rename even if they want to overwrite the
target if it exists. So removing the read only flag is required.

Signed-off-by: Dmitry Torokhov <dtor@vmware.com>
open-vm-tools/modules/linux/vmhgfs/inode.c

index 60bb31a16e6c8cbc5b249b483baec1bbf06c036f..2999b9406ed80b4d8e49ba4a8e3f4ba403284b2c 100644 (file)
@@ -158,6 +158,38 @@ struct inode_operations HgfsFileInodeOperations = {
  * Private functions implementations.
  */
 
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HgfsClearReadOnly --
+ *
+ *    Try to remove the file/dir read only attribute.
+ *
+ *    Note when running on Windows servers the entry may have the read-only
+ *    flag set and prevent a rename or delete operation from occuring.
+ *
+ * Results:
+ *    Returns zero on success, or a negative error on failure.
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+HgfsClearReadOnly(struct dentry *dentry)  // IN: file/dir to remove read only
+{
+   struct iattr enableWrite;
+
+   LOG(4, (KERN_DEBUG "VMware hgfs: HgfsClearReadOnly: removing read-only\n"));
+   enableWrite.ia_mode = (dentry->d_inode->i_mode | S_IWUSR);
+   enableWrite.ia_valid = ATTR_MODE;
+   return HgfsSetattr(dentry, &enableWrite);
+}
+
+
 /*
  *----------------------------------------------------------------------
  *
@@ -308,14 +340,8 @@ HgfsDelete(struct inode *dir,      // IN: Parent dir of file/dir to delete
           * safe?
           */
          if (!secondAttempt) {
-            struct iattr enableWrite;
             secondAttempt = TRUE;
-
-            LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: access denied, "
-                    "attempting to work around read-only bit\n"));
-            enableWrite.ia_mode = (dentry->d_inode->i_mode | S_IWUSR);
-            enableWrite.ia_valid = ATTR_MODE;
-            result = HgfsSetattr(dentry, &enableWrite);
+            result = HgfsClearReadOnly(dentry);
             if (result == 0) {
                LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: file is no "
                        "longer read-only, retrying delete\n"));
@@ -1325,6 +1351,7 @@ HgfsRename(struct inode *oldDir,      // IN: Inode of original directory
    HgfsReq *req = NULL;
    char *oldName;
    char *newName;
+   Bool secondAttempt=FALSE;
    uint32 *oldNameLength;
    uint32 *newNameLength;
    int result = 0;
@@ -1489,6 +1516,31 @@ retry:
                     "returned error: %d\n", result));
             goto out;
          }
+      } else if ((-EACCES == result) || (-EPERM == result)) {
+         /*
+          * It's possible that we're talking to a Windows server with
+          * a file marked read-only. Let's try again, after removing
+          * the read-only bit from the file.
+          *
+          * XXX: I think old servers will send -EPERM here. Is this entirely
+          * safe?
+          */
+         if (!secondAttempt) {
+            secondAttempt = TRUE;
+            result = HgfsClearReadOnly(newDentry);
+            if (result == 0) {
+               LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: file is no "
+                       "longer read-only, retrying rename\n"));
+               goto retry;
+            }
+            LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: failed to remove "
+                    "read-only property\n"));
+         } else {
+            LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: second attempt at "
+                    "rename failed\n"));
+         }
+      } else if (0 != result) {
+         LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: failed with result %d\n", result));
       }
    } else if (result == -EIO) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: timed out\n"));