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; }
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; }