newSearch->dents = NULL;
newSearch->numDents = 0;
+ newSearch->flags = 0;
newSearch->type = type;
newSearch->handle = HgfsServerGetNextHandleCounter();
}
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSearchHasReadAllEntries --
+ *
+ * Return whether the client has read all the search entries or not.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure. readAllEntries is filled in on
+ * success.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsSearchHasReadAllEntries(HgfsHandle handle, // IN: Hgfs file handle
+ HgfsSessionInfo *session, // IN: Session info
+ Bool *readAllEntries) // OUT: If open was sequential
+{
+ HgfsSearch *search;
+ Bool success = FALSE;
+
+ ASSERT(NULL != readAllEntries);
+
+ MXUser_AcquireExclLock(session->searchArrayLock);
+
+ search = HgfsSearchHandle2Search(handle, session);
+ if (NULL == search) {
+ goto exit;
+ }
+
+ *readAllEntries = search->flags & HGFS_SEARCH_FLAG_READ_ALL_ENTRIES;
+ success = TRUE;
+
+exit:
+ MXUser_ReleaseExclLock(session->searchArrayLock);
+
+ return success;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSearchSetReadAllEntries --
+ *
+ * Set the flag to indicate the client has read all the search entries.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+HgfsSearchSetReadAllEntries(HgfsHandle handle, // IN: Hgfs file handle
+ HgfsSessionInfo *session) // IN: Session info
+{
+ HgfsSearch *search;
+
+ MXUser_AcquireExclLock(session->searchArrayLock);
+
+ search = HgfsSearchHandle2Search(handle, session);
+ if (NULL == search) {
+ goto exit;
+ }
+
+ search->flags |= HGFS_SEARCH_FLAG_READ_ALL_ENTRIES;
+
+exit:
+ MXUser_ReleaseExclLock(session->searchArrayLock);
+}
+
+
/*
*-----------------------------------------------------------------------------
*
/*
*-----------------------------------------------------------------------------
*
- * HgfsServerGetDents --
+ * HgfsServerScanvdir --
+ *
+ * Perform a scandir on our virtual directory.
*
* Get directory entry names from the given callback function, and
* build an array of DirectoryEntrys of all the names. Somewhat similar to
*/
static int
-HgfsServerGetDents(HgfsGetNameFunc getName, // IN: Function to get name
+HgfsServerScanvdir(HgfsGetNameFunc getName, // IN: Function to get name
HgfsInitFunc initName, // IN: Setup function
HgfsCleanupFunc cleanupName, // IN: Cleanup function
DirectoryEntry ***dents) // OUT: Array of DirectoryEntrys
{
HgfsInternalStatus status = 0;
HgfsSearch *search = NULL;
- int result = 0;
+ int scanDirResult;
ASSERT(getName);
ASSERT(initName);
goto out;
}
- result = HgfsServerGetDents(getName, initName, cleanupName, &search->dents);
- if (result < 0) {
+ scanDirResult = HgfsServerScanvdir(getName, initName, cleanupName, &search->dents);
+ if (scanDirResult < 0) {
LOG(4, ("%s: couldn't get dents\n", __FUNCTION__));
HgfsRemoveSearchInternal(search, session);
status = HGFS_ERROR_INTERNAL;
goto out;
}
- search->numDents = result;
+ search->numDents = scanDirResult;
*handle = HgfsSearch2SearchHandle(search);
out:
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsServerRestartSearchVirtualDir --
+ *
+ * Restart a search on a virtual directory (i.e. one that does not
+ * really exist on the server). Takes a pointer to an enumerator
+ * for the directory's contents and returns a handle to a search that is
+ * correctly set up with the virtual directory's entries.
+ *
+ * Results:
+ * Zero on success, returns a handle to the created search.
+ * Non-zero on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+HgfsInternalStatus
+HgfsServerRestartSearchVirtualDir(HgfsGetNameFunc *getName, // IN: Name enumerator
+ HgfsInitFunc *initName, // IN: Init function
+ HgfsCleanupFunc *cleanupName, // IN: Cleanup function
+ HgfsSessionInfo *session, // IN: Session info
+ HgfsHandle searchHandle) // IN: search to restart
+{
+ HgfsInternalStatus status = 0;
+ HgfsSearch *vdirSearch;
+ int scanDirResult;
+
+ ASSERT(getName);
+ ASSERT(initName);
+ ASSERT(cleanupName);
+ ASSERT(searchHandle);
+
+ MXUser_AcquireExclLock(session->searchArrayLock);
+
+ vdirSearch = HgfsSearchHandle2Search(searchHandle, session);
+ if (NULL == vdirSearch) {
+ status = HGFS_ERROR_INVALID_HANDLE;
+ goto exit;
+ }
+
+ /* Release the virtual directory's old set of entries. */
+ HgfsFreeSearchDirents(vdirSearch);
+
+ /* Restart by rescanning the virtual directory. */
+ scanDirResult = HgfsServerScanvdir(getName,
+ initName,
+ cleanupName,
+ &vdirSearch->dents);
+ if (scanDirResult < 0) {
+ ASSERT_DEVEL(0);
+ LOG(4, ("%s: couldn't get root dents\n", __FUNCTION__));
+ vdirSearch->numDents = 0;
+ status = HGFS_ERROR_INTERNAL;
+ }
+
+ vdirSearch->numDents = scanDirResult;
+ /* Clear the flag to indicate that the client has read the entries. */
+ vdirSearch->flags &= ~HGFS_SEARCH_FLAG_READ_ALL_ENTRIES;
+
+exit:
+ MXUser_ReleaseExclLock(session->searchArrayLock);
+
+ LOG(4, ("%s: refreshing dents return %d\n", __FUNCTION__, status));
+ return status;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
*nameLength = 0;
*moreEntries = FALSE;
info->replyFlags |= HGFS_SEARCH_READ_REPLY_FINAL_ENTRY;
+ HgfsSearchSetReadAllEntries(hgfsSearchHandle, session);
}
return status;
}
status = HGFS_ERROR_FILE_NOT_FOUND;
}
} else if (0 == info.startIndex) {
- HgfsSearch *rootSearch;
-
- MXUser_AcquireExclLock(input->session->searchArrayLock);
-
- rootSearch = HgfsSearchHandle2Search(hgfsSearchHandle, input->session);
- ASSERT(NULL != rootSearch);
- HgfsFreeSearchDirents(rootSearch);
-
- rootSearch->numDents =
- HgfsServerGetDents(HgfsServerPolicy_GetShares,
- HgfsServerPolicy_GetSharesInit,
- HgfsServerPolicy_GetSharesCleanup,
- &rootSearch->dents);
- if (((int) (rootSearch->numDents)) < 0) {
- ASSERT_DEVEL(0);
- LOG(4, ("%s: couldn't get root dents\n", __FUNCTION__));
- rootSearch->numDents = 0;
+ Bool readAllEntries = FALSE;
+
+ /*
+ * Reading the first entry, we check if this is a second scan
+ * of the directory. If so, in some cases we restart the scan
+ * by refreshing the entries first.
+ */
+ if (!HgfsSearchHasReadAllEntries(hgfsSearchHandle,
+ input->session,
+ &readAllEntries)) {
status = HGFS_ERROR_INTERNAL;
}
- MXUser_ReleaseExclLock(input->session->searchArrayLock);
+ if (readAllEntries) {
+ /*
+ * XXX - a hack that is now required until Fusion 5.0 end
+ * of lifes see bug 710697.
+ * The coder modified the server instead of the OS X client
+ * for the shares directory refresh needed by OS X clients in
+ * order to work around handles remaining open by Finder.
+ * This was fixed CLN 1988575 in the OS X client for 5.0.2.
+ * However, Fusion 4.0 and Fusion 5.0 tools will rely on this hack.
+ * At least now it works correctly without breaking everything
+ * else.
+ */
+ status = HgfsPlatformRestartSearchDir(hgfsSearchHandle,
+ input->session,
+ search.type);
+ }
}
if (HGFS_ERROR_SUCCESS == status) {
/* Links to place the object on various lists */
DblLnkLst_Links links;
+ /* Flags to track state and information: see below. */
+ uint32 flags;
+
/* HGFS handle uniquely identifying this search. */
HgfsHandle handle;
HgfsShareInfo shareInfo;
} HgfsSearch;
+/* HgfsSearch flags. */
+
+/* TRUE if opened in append mode */
+#define HGFS_SEARCH_FLAG_READ_ALL_ENTRIES (1 << 0)
+
/* HgfsSessionInfo flags. */
typedef enum {
HGFS_SESSION_TYPE_REGULAR, /* Dynamic session, created by the HgfsTransport. */
HgfsSessionInfo *session, // IN: Session info
HgfsHandle *handle); // OUT: Search handle
+HgfsInternalStatus
+HgfsServerRestartSearchVirtualDir(HgfsGetNameFunc *getName, // IN: Name enumerator
+ HgfsInitFunc *initName, // IN: Init function
+ HgfsCleanupFunc *cleanupName, // IN: Cleanup function
+ HgfsSessionInfo *session, // IN: Session info
+ HgfsHandle searchHandle); // IN: search to restart
+
/* Allocate/Add sessions helper functions. */
Bool HgfsServerAllocateSession(HgfsTransportSessionInfo *transportSession,
HgfsSessionInfo *session, // IN: session info
HgfsHandle *handle); // OUT: search handle
HgfsInternalStatus
-HgfsAccess(char *fileName, // IN: local file path
- char *shareName, // IN: Name of the share
- size_t shareNameLen); // IN: Length of the share name
+HgfsPlatformRestartSearchDir(HgfsHandle handle, // IN: search handle
+ HgfsSessionInfo *session, // IN: session info
+ DirectorySearchType searchType); // IN: Kind of search
HgfsInternalStatus
HgfsPlatformReadFile(HgfsHandle file, // IN: Hgfs file handle
HgfsSessionInfo *session, // IN: session info