int CPNameEscapeAndConvertFrom(char const **bufIn, // IN/OUT: Input to convert size_t *inSize, // IN/OUT: Size of input size_t *outSize, // IN/OUT: Size of output buffer char **bufOut, // IN/OUT: Output buffer char pathSep) // IN: Path separator character { int result; int inputSize; inputSize = HgfsEscape_GetSize(*bufIn, *inSize); if (inputSize < 0) { result = -1; } else if (inputSize != 0) { char *savedBufOut = *bufOut; char const *savedOutConst = savedBufOut; size_t savedOutSize = *outSize; if (inputSize > *outSize) { Log("%s: error: not enough room for escaping\n", __FUNCTION__); return -1; } /* Leaving space for the leading path separator, thus output to savedBufOut + 1. */ *inSize = HgfsEscape_Do(*bufIn, *inSize, savedOutSize, savedBufOut + 1); result = CPNameConvertFrom(&savedOutConst, inSize, outSize, bufOut, pathSep); *bufIn += *inSize; *inSize = 0; } else { result = CPNameConvertFrom(bufIn, inSize, outSize, bufOut, pathSep); } return result; }
static Bool HgfsClient_PrintShares(void) { Bool success = FALSE; int offset = 0; char escapedName[PATH_MAX + 1]; HgfsHandle rootHandle; HgfsFileName *fileName; if (!HgfsClient_Open(&rootHandle)) { return success; } while (TRUE) { fileName = HgfsClient_Read(rootHandle, offset++); if (fileName == NULL) { break; } /* Are we done? */ if (fileName->length == 0) { success = TRUE; break; } /* * Escape this filename. If we get back a negative result, it means that * the escaped filename is too big, so skip this share. */ if (HgfsEscape_Do(fileName->name, fileName->length, sizeof escapedName, escapedName) < 0) { continue; } /* Skip "." and ".." which can be returned. */ if (strcmp(".", escapedName) == 0 || strcmp("..", escapedName) == 0) { continue; } printf("%s\n", escapedName); } if (!HgfsClient_Close(rootHandle)) { success = FALSE; } return success; }
static int HgfsReaddirNextEntry(struct file *file, // IN: file loff_t entryPos, // IN: position Bool dotAndDotDotIgnore, // IN: ignore "." and ".." size_t entryNameBufLen, // IN: name buffer length char *entryName, // OUT: entry name uint32 *entryNameLength, // OUT: max name length ino_t *entryIno, // OUT: inode entry number uint32 *entryType, // OUT: entry type Bool *entryIgnore, // OUT: ignore this entry or not Bool *entryEnd) // OUT: no more entries { HgfsSuperInfo *si; HgfsAttrInfo entryAttrs; char *fileName = NULL; int result; ASSERT(file->f_dentry->d_inode->i_sb); #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) si = HGFS_SB_TO_COMMON(file->f_dentry->d_inode->i_sb); #else si = HGFS_SB_TO_COMMON(file->f_path.dentry->d_inode->i_sb); #endif *entryIgnore = FALSE; /* * Nonzero result = we failed to get valid reply from server. * Zero result: * - done == TRUE means we hit the end of the directory * - Otherwise, fileName has the name of the next dirent * */ result = HgfsGetNextDirEntry(si, FILE_GET_FI_P(file)->handle, (uint32)entryPos, &entryAttrs, &fileName, entryEnd); if (result == -ENAMETOOLONG) { /* * Skip dentry if its name is too long (see below). * * XXX: If a bad server sends us bad packets, we can loop here * forever, as I did while testing *grumble*. Maybe we should error * in that case. */ LOG(4, (KERN_DEBUG "VMware hgfs: %s: error getnextdentry name %d\n", __func__, result)); *entryIgnore = TRUE; result = 0; goto exit; } else if (result) { /* Error */ LOG(4, (KERN_DEBUG "VMware hgfs: %s: error getnextdentry %d\n", __func__, result)); goto exit; } if (*entryEnd) { LOG(10, (KERN_DEBUG "VMware hgfs: %s: end of dir reached\n", __func__)); goto exit; } /* * Escape all non-printable characters (which for linux is just * "/"). * * Note that normally we would first need to convert from the * CP name format, but that is done implicitely here since we * are guaranteed to have just one path component per dentry. */ result = HgfsEscape_Do(fileName, strlen(fileName), entryNameBufLen, entryName); kfree(fileName); fileName = NULL; /* * Check the filename length. * * If the name is too long to be represented in linux, we simply * skip it (i.e., that file is not visible to our filesystem). * * HgfsEscape_Do returns a negative value if the escaped * output didn't fit in the specified output size, so we can * just check its return value. */ if (result < 0) { /* * XXX: Another area where a bad server could cause us to loop * forever. */ *entryIgnore = TRUE; result = 0; goto exit; } *entryNameLength = result; result = 0; /* * It is unfortunate, but the HGFS server sends back '.' and ".." * when we do a SearchRead. In an ideal world, these would be faked * on the client, but it would be a real backwards-compatibility * hassle to change the behavior at this point. * * So instead, we'll take the '.' and ".." and modify their inode * numbers so they match what the client expects. */ if (!strncmp(entryName, ".", sizeof ".")) { if (!dotAndDotDotIgnore) { #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) *entryIno = file->f_dentry->d_inode->i_ino; #else *entryIno = file->f_path.dentry->d_inode->i_ino; #endif } else { *entryIgnore = TRUE; } } else if (!strncmp(entryName, "..", sizeof "..")) { if (!dotAndDotDotIgnore) { #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) *entryIno = compat_parent_ino(file->f_dentry); #else *entryIno = compat_parent_ino(file->f_path.dentry); #endif } else { *entryIgnore = TRUE; } } else { #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) *entryIno = HgfsGetFileInode(&entryAttrs, file->f_dentry->d_inode->i_sb); #else *entryIno = HgfsGetFileInode(&entryAttrs, file->f_path.dentry->d_inode->i_sb); #endif } if (*entryIgnore) { goto exit; } /* Assign the correct dentry type. */ *entryType = HgfsGetFileType(&entryAttrs); exit: return result; }