Esempio n. 1
0
static int
HgfsDirOpen(struct inode *inode,  // IN: Inode of the dir to open
            struct file *file)    // IN: File pointer for this open
{
   int result;

   HgfsHandle handle;

   ASSERT(inode);
   ASSERT(inode->i_sb);
   ASSERT(file);

   result = HgfsPrivateDirOpen(file, &handle);
   if (!result) {
      result = HgfsCreateFileInfo(file, handle);
   }

   return result;
}
Esempio n. 2
0
static int
HgfsOpen(struct inode *inode,  // IN: Inode of the file to open
         struct file *file)    // IN: File pointer for this open
{
   HgfsReq *req;
   HgfsOp opUsed;
   HgfsStatus replyStatus;
   HgfsHandle replyFile;
   HgfsServerLock replyLock;
   HgfsInodeInfo *iinfo;
   int result = 0;

   ASSERT(inode);
   ASSERT(inode->i_sb);
   ASSERT(file);
   ASSERT(file->f_dentry);
   ASSERT(file->f_dentry->d_inode);

   iinfo = INODE_GET_II_P(inode);

   req = HgfsGetNewRequest();
   if (!req) {
      LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: out of memory while "
              "getting new request\n"));
      result = -ENOMEM;
      goto out;
   }

  retry:
   /*
    * Set up pointers using the proper struct This lets us check the
    * version exactly once and use the pointers later.
    */

   opUsed = hgfsVersionOpen;
   result = HgfsPackOpenRequest(inode, file, opUsed, req);
   if (result != 0) {
      LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: error packing request\n"));
      goto out;
   }

   /* Send the request and process the reply. */
   result = HgfsSendRequest(req);
   if (result == 0) {
      /* Get the reply and check return status. */
      replyStatus = HgfsReplyStatus(req);
      result = HgfsStatusConvertToLinux(replyStatus);

      switch (result) {
      case 0:
         iinfo->createdAndUnopened = FALSE;
         LOG(10, (KERN_DEBUG "VMware hgfs: HgfsOpen: old hostFileId = "
                  "%"FMT64"u\n", iinfo->hostFileId));
         /*
          * Invalidate the hostFileId as we need to retrieve it from
          * the server.
          */
         iinfo->hostFileId = 0;
         result = HgfsUnpackOpenReply(req, opUsed, &replyFile, &replyLock);
         if (result != 0) {
            break;
         }
         result = HgfsCreateFileInfo(file, replyFile);
         if (result != 0) {
            break;
         }
         LOG(6, (KERN_DEBUG "VMware hgfs: HgfsOpen: set handle to %u\n",
                 replyFile));

         /*
          * HgfsCreate faked all of the inode's attributes, so by the time
          * we're done in HgfsOpen, we need to make sure that the attributes
          * in the inode are real. The following is only necessary when
          * O_CREAT is set, otherwise we got here after HgfsLookup (which sent
          * a getattr to the server and got the real attributes).
          *
          * In particular, we'd like to at least try and set the inode's
          * uid/gid to match the caller's. We don't expect this to work,
          * because Windows servers will ignore it, and Linux servers running
          * as non-root won't be able to change it, but we're forward thinking
          * people.
          *
          * Either way, we force a revalidate following the setattr so that
          * we'll get the actual uid/gid from the server.
          */
         if (file->f_flags & O_CREAT) {
            struct dentry *dparent;
            struct inode *iparent;

            /*
             * This is not the root of our file system so there should always
             * be a parent.
             */
            ASSERT(file->f_dentry->d_parent);

            /*
             * Here we obtain a reference on the parent to make sure it doesn't
             * go away.  This might not be necessary, since the existence of
             * a child (which we hold a reference to in this call) should
             * account for a reference in the parent, but it's safe to do so.
             * Overly cautious and safe is better than risky and broken.
             *
             * XXX Note that this and a handful of other hacks wouldn't be
             * necessary if we actually created the file in our create
             * implementation (where references and locks are properly held).
             * We could do this if we were willing to give up support for
             * O_EXCL on 2.4 kernels.
             */
            dparent = dget(file->f_dentry->d_parent);
            iparent = dparent->d_inode;

            HgfsSetUidGid(iparent, file->f_dentry,
                          current_fsuid(), current_fsgid());

            dput(dparent);
         }
         break;

      case -EPROTO:
         /* Retry with older version(s). Set globally. */
         if (opUsed == HGFS_OP_OPEN_V3) {
            LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: Version 3 not "
                    "supported. Falling back to version 2.\n"));
            hgfsVersionOpen = HGFS_OP_OPEN_V2;
            goto retry;
         }

         /* Retry with Version 1 of Open. Set globally. */
         if (opUsed == HGFS_OP_OPEN_V2) {
            LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: Version 2 not "
                    "supported. Falling back to version 1.\n"));
            hgfsVersionOpen = HGFS_OP_OPEN;
            goto retry;
         }

         /* Fallthrough. */
      default:
         break;
      }
   } else if (result == -EIO) {
      LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: timed out\n"));
   } else if (result == -EPROTO) {
      LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: server "
              "returned error: %d\n", result));
   } else {
      LOG(4, (KERN_DEBUG "VMware hgfs: HgfsOpen: unknown error: "
              "%d\n", result));
   }
out:
   HgfsFreeRequest(req);

   /*
    * If the open failed (for any reason) and we tried to open a newly created
    * file, we must ensure that the next operation on this inode triggers a
    * revalidate to the server. This is because the file wasn't created on the
    * server, yet we currently believe that it was, because we created a fake
    * inode with a hashed dentry for it in HgfsCreate. We will continue to
    * believe this until the dentry's ttl expires, which will cause a
    * revalidate to the server that will reveal the truth. So in order to find
    * the truth as soon as possible, we'll reset the dentry's last revalidate
    * time now to force a revalidate the next time someone uses the dentry.
    *
    * We're using our own flag to track this case because using O_CREAT isn't
    * good enough: HgfsOpen will be called with O_CREAT even if the file exists
    * on the server, and if that's the case, there's no need to revalidate.
    *
    * XXX: Note that this will need to be reworked if/when we support hard
    * links, because multiple dentries will point to the same inode, and
    * forcing a revalidate on one will not force it on any others.
    */
   if (result != 0 && iinfo->createdAndUnopened == TRUE) {
      HgfsDentryAgeForce(file->f_dentry);
   }
   return result;
}