From: VMware, Inc <> Date: Wed, 26 Dec 2012 21:21:22 +0000 (-0800) Subject: HGFS: Cleanup the directory entry code to be really platform specific - part I X-Git-Tag: 2012.12.26-958366~22 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=54d2fb92f4d6ff41925bdcd2d01549e6c0cf7510;p=thirdparty%2Fopen-vm-tools.git HGFS: Cleanup the directory entry code to be really platform specific - part I The directory entry work is very inefficient and will cause oplock issues. For Windows platforms the directory reads will change and thus the assumptions about the platform specific DirectoryEntry structure will not hold true. Therefore, the DirectoryEntry code is moving to the platform specific files and will allow the code to have complete control over the structure and contents. Initially, there will be some duplication of code but that will change in later work. There is already bugs with this code and places where ifdefs are added for platform specific cases not handled by some platforms. These should not be in platform independent code. The volume query is also broken and misses some of the Windows platform specific cases completely which should be handled and will be in the Windows only code. (Again, later change sets.) For now, this just simply moves a routine out of the common code into the platform specific code. More changes to follow. Signed-off-by: Dmitry Torokhov --- diff --git a/open-vm-tools/lib/hgfsServer/hgfsServer.c b/open-vm-tools/lib/hgfsServer/hgfsServer.c index 9f1da8112..ef5a16e38 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServer.c +++ b/open-vm-tools/lib/hgfsServer/hgfsServer.c @@ -5004,175 +5004,6 @@ HgfsServerDumpDents(HgfsHandle searchHandle, // IN: Handle to dump dents from } -/* - *----------------------------------------------------------------------------- - * - * 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 - * scandir(3) on linux, but more general. - * - * Results: - * On success, the number of directory entries found. - * On failure, negative error. - * - * Side effects: - * Memory allocation. - * - *----------------------------------------------------------------------------- - */ - -static HgfsInternalStatus -HgfsServerScanvdir(HgfsGetNameFunc enumNamesGet, // IN: Function to get name - HgfsInitFunc enumNamesInit, // IN: Setup function - HgfsCleanupFunc enumNamesExit, // IN: Cleanup function - DirectoryEntry ***dents, // OUT: Array of DirectoryEntrys - uint32 *numDents) // OUT: total number of directory entrys -{ - HgfsInternalStatus status = HGFS_ERROR_SUCCESS; - uint32 totalDents = 0; // Number of allocated dents - uint32 myNumDents = 0; // Current actual number of dents - DirectoryEntry **myDents = NULL; // So realloc is happy w/ zero myNumDents - void *enumNamesHandle; - - ASSERT(NULL != enumNamesInit); - ASSERT(NULL != enumNamesGet); - ASSERT(NULL != enumNamesExit); - - enumNamesHandle = enumNamesInit(); - if (NULL == enumNamesHandle) { - status = HGFS_ERROR_NOT_ENOUGH_MEMORY; - LOG(4, ("%s: Error: init state ret %u\n", __FUNCTION__, status)); - goto exit; - } - - for (;;) { - DirectoryEntry *currentEntry; - char const *currentEntryName; - size_t currentEntryNameLen; - size_t currentEntryLen; - size_t maxNameLen; - Bool done = FALSE; - - /* Add '.' and ".." as the first dents. */ - if (myNumDents == 0) { - currentEntryName = "."; - currentEntryNameLen = 1; - } else if (myNumDents == 1) { - currentEntryName = ".."; - currentEntryNameLen = 2; - } else { - if (!enumNamesGet(enumNamesHandle, ¤tEntryName, ¤tEntryNameLen, &done)) { - status = HGFS_ERROR_INVALID_PARAMETER; - LOG(4, ("%s: Error: get next entry name ret %u\n", __FUNCTION__, status)); - goto exit; - } - } - - if (done) { - LOG(4, ("%s: No more names\n", __FUNCTION__)); - break; - } - -#if defined(sun) - /* - * Solaris lacks a single definition of NAME_MAX and using pathconf(), to - * determine NAME_MAX for the current directory, is too cumbersome for - * our purposes, so we use PATH_MAX as a reasonable upper bound on the - * length of the name. - */ - maxNameLen = PATH_MAX; -#else - maxNameLen = sizeof currentEntry->d_name; -#endif - if (currentEntryNameLen >= maxNameLen) { - Log("%s: Error: Name \"%s\" is too long.\n", __FUNCTION__, currentEntryName); - continue; - } - - /* See if we need to allocate more memory */ - if (myNumDents == totalDents) { - void *p; - - if (totalDents != 0) { - totalDents *= 2; - } else { - totalDents = 100; - } - p = realloc(myDents, totalDents * sizeof *myDents); - if (NULL == p) { - status = HGFS_ERROR_NOT_ENOUGH_MEMORY; - LOG(4, ("%s: Error: realloc growing array memory ret %u\n", __FUNCTION__, status)); - goto exit; - } - myDents = p; - } - - /* This file/directory can be added to the list. */ - LOG(4, ("%s: Nextfilename = \"%s\"\n", __FUNCTION__, currentEntryName)); - - /* - * Start with the size of the DirectoryEntry struct, subtract the static - * length of the d_name buffer (256 in Linux, 1 in Solaris, etc) and add - * back just enough space for the UTF-8 name and nul terminator. - */ - - currentEntryLen = offsetof(DirectoryEntry, d_name) + currentEntryNameLen + 1; - currentEntry = malloc(currentEntryLen); - if (NULL == currentEntry) { - status = HGFS_ERROR_NOT_ENOUGH_MEMORY; - LOG(4, ("%s: Error: allocate dentry memory ret %u\n", __FUNCTION__, status)); - goto exit; - } - currentEntry->d_reclen = (unsigned short)currentEntryLen; - memcpy(currentEntry->d_name, currentEntryName, currentEntryNameLen); - currentEntry->d_name[currentEntryNameLen] = 0; - - myDents[myNumDents] = currentEntry; - myNumDents++; - } - - /* Trim extra memory off of dents */ - { - void *p; - - p = realloc(myDents, myNumDents * sizeof *myDents); - if (NULL != p) { - myDents = p; - } else { - LOG(4, ("%s: Error: realloc trimming array memory\n", __FUNCTION__)); - } - } - - *dents = myDents; - *numDents = myNumDents; - -exit: - if (NULL != enumNamesHandle) { - /* Call the exit callback to teardown any state. */ - if (!enumNamesExit(enumNamesHandle)) { - LOG(4, ("%s: Error cleanup failed\n", __FUNCTION__)); - } - } - - if (HGFS_ERROR_SUCCESS != status) { - unsigned int i; - - /* Free whatever has been allocated so far */ - for (i = 0; i < myNumDents; i++) { - free(myDents[i]); - } - - free(myDents); - } - - return status; -} - - /* *----------------------------------------------------------------------------- * @@ -5300,11 +5131,11 @@ HgfsServerSearchVirtualDir(HgfsGetNameFunc *getName, // IN: Name enumerator goto out; } - status = HgfsServerScanvdir(getName, - initName, - cleanupName, - &search->dents, - &search->numDents); + status = HgfsPlatformScanvdir(getName, + initName, + cleanupName, + &search->dents, + &search->numDents); if (HGFS_ERROR_SUCCESS != status) { LOG(4, ("%s: couldn't get dents\n", __FUNCTION__)); HgfsRemoveSearchInternal(search, session); @@ -5367,11 +5198,11 @@ HgfsServerRestartSearchVirtualDir(HgfsGetNameFunc *getName, // IN: Name enum HgfsFreeSearchDirents(vdirSearch); /* Restart by rescanning the virtual directory. */ - status = HgfsServerScanvdir(getName, - initName, - cleanupName, - &vdirSearch->dents, - &vdirSearch->numDents); + status = HgfsPlatformScanvdir(getName, + initName, + cleanupName, + &vdirSearch->dents, + &vdirSearch->numDents); if (HGFS_ERROR_SUCCESS != status) { ASSERT_DEVEL(0); LOG(4, ("%s: couldn't get root dents %u\n", __FUNCTION__, status)); diff --git a/open-vm-tools/lib/hgfsServer/hgfsServerInt.h b/open-vm-tools/lib/hgfsServer/hgfsServerInt.h index feb1afb24..0b38ad195 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServerInt.h +++ b/open-vm-tools/lib/hgfsServer/hgfsServerInt.h @@ -1132,6 +1132,12 @@ HgfsPlatformScandir(char const *baseDir, // IN: Directory to search in DirectoryEntry ***dents, // OUT: Array of DirectoryEntrys int *numDents); // OUT: Number of DirectoryEntrys HgfsInternalStatus +HgfsPlatformScanvdir(HgfsGetNameFunc enumNamesGet, // IN: Function to get name + HgfsInitFunc enumNamesInit, // IN: Setup function + HgfsCleanupFunc enumNamesExit, // IN: Cleanup function + DirectoryEntry ***dents, // OUT: Array of DirectoryEntrys + uint32 *numDents); // OUT: total number of directory entrys +HgfsInternalStatus HgfsPlatformSearchDir(HgfsNameStatus nameStatus, // IN: name status char *dirName, // IN: relative directory name uint32 dirNameLength, // IN: length of dirName diff --git a/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c b/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c index 4e3bfe212..dff010695 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c +++ b/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c @@ -3253,6 +3253,175 @@ HgfsPlatformScandir(char const *baseDir, // IN: Directory to search in } +/* + *----------------------------------------------------------------------------- + * + * HgfsPlatformScanvdir -- + * + * 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 + * scandir(3) on linux, but more general. + * + * Results: + * On success, the number of directory entries found. + * On failure, negative error. + * + * Side effects: + * Memory allocation. + * + *----------------------------------------------------------------------------- + */ + +HgfsInternalStatus +HgfsPlatformScanvdir(HgfsGetNameFunc enumNamesGet, // IN: Function to get name + HgfsInitFunc enumNamesInit, // IN: Setup function + HgfsCleanupFunc enumNamesExit, // IN: Cleanup function + DirectoryEntry ***dents, // OUT: Array of DirectoryEntrys + uint32 *numDents) // OUT: total number of directory entrys +{ + HgfsInternalStatus status = HGFS_ERROR_SUCCESS; + uint32 totalDents = 0; // Number of allocated dents + uint32 myNumDents = 0; // Current actual number of dents + DirectoryEntry **myDents = NULL; // So realloc is happy w/ zero myNumDents + void *enumNamesHandle; + + ASSERT(NULL != enumNamesInit); + ASSERT(NULL != enumNamesGet); + ASSERT(NULL != enumNamesExit); + + enumNamesHandle = enumNamesInit(); + if (NULL == enumNamesHandle) { + status = HGFS_ERROR_NOT_ENOUGH_MEMORY; + LOG(4, ("%s: Error: init state ret %u\n", __FUNCTION__, status)); + goto exit; + } + + for (;;) { + DirectoryEntry *currentEntry; + char const *currentEntryName; + size_t currentEntryNameLen; + size_t currentEntryLen; + size_t maxNameLen; + Bool done = FALSE; + + /* Add '.' and ".." as the first dents. */ + if (myNumDents == 0) { + currentEntryName = "."; + currentEntryNameLen = 1; + } else if (myNumDents == 1) { + currentEntryName = ".."; + currentEntryNameLen = 2; + } else { + if (!enumNamesGet(enumNamesHandle, ¤tEntryName, ¤tEntryNameLen, &done)) { + status = HGFS_ERROR_INVALID_PARAMETER; + LOG(4, ("%s: Error: get next entry name ret %u\n", __FUNCTION__, status)); + goto exit; + } + } + + if (done) { + LOG(4, ("%s: No more names\n", __FUNCTION__)); + break; + } + +#if defined(sun) + /* + * Solaris lacks a single definition of NAME_MAX and using pathconf(), to + * determine NAME_MAX for the current directory, is too cumbersome for + * our purposes, so we use PATH_MAX as a reasonable upper bound on the + * length of the name. + */ + maxNameLen = PATH_MAX; +#else + maxNameLen = sizeof currentEntry->d_name; +#endif + if (currentEntryNameLen >= maxNameLen) { + Log("%s: Error: Name \"%s\" is too long.\n", __FUNCTION__, currentEntryName); + continue; + } + + /* See if we need to allocate more memory */ + if (myNumDents == totalDents) { + void *p; + + if (totalDents != 0) { + totalDents *= 2; + } else { + totalDents = 100; + } + p = realloc(myDents, totalDents * sizeof *myDents); + if (NULL == p) { + status = HGFS_ERROR_NOT_ENOUGH_MEMORY; + LOG(4, ("%s: Error: realloc growing array memory ret %u\n", __FUNCTION__, status)); + goto exit; + } + myDents = p; + } + + /* This file/directory can be added to the list. */ + LOG(4, ("%s: Nextfilename = \"%s\"\n", __FUNCTION__, currentEntryName)); + + /* + * Start with the size of the DirectoryEntry struct, subtract the static + * length of the d_name buffer (256 in Linux, 1 in Solaris, etc) and add + * back just enough space for the UTF-8 name and nul terminator. + */ + + currentEntryLen = offsetof(DirectoryEntry, d_name) + currentEntryNameLen + 1; + currentEntry = malloc(currentEntryLen); + if (NULL == currentEntry) { + status = HGFS_ERROR_NOT_ENOUGH_MEMORY; + LOG(4, ("%s: Error: allocate dentry memory ret %u\n", __FUNCTION__, status)); + goto exit; + } + currentEntry->d_reclen = (unsigned short)currentEntryLen; + memcpy(currentEntry->d_name, currentEntryName, currentEntryNameLen); + currentEntry->d_name[currentEntryNameLen] = 0; + + myDents[myNumDents] = currentEntry; + myNumDents++; + } + + /* Trim extra memory off of dents */ + { + void *p; + + p = realloc(myDents, myNumDents * sizeof *myDents); + if (NULL != p) { + myDents = p; + } else { + LOG(4, ("%s: Error: realloc trimming array memory\n", __FUNCTION__)); + } + } + + *dents = myDents; + *numDents = myNumDents; + +exit: + if (NULL != enumNamesHandle) { + /* Call the exit callback to teardown any state. */ + if (!enumNamesExit(enumNamesHandle)) { + LOG(4, ("%s: Error cleanup failed\n", __FUNCTION__)); + } + } + + if (HGFS_ERROR_SUCCESS != status) { + unsigned int i; + + /* Free whatever has been allocated so far */ + for (i = 0; i < myNumDents; i++) { + free(myDents[i]); + } + + free(myDents); + } + + return status; +} + + /* *---------------------------------------------------------------------- *