Set the FILESYSANCESTOR and FILESYSTEM flags correctly in

GetAttributesOf.
oldstable
Michael Jung 2005-06-10 19:31:59 +00:00 committed by Alexandre Julliard
parent 3fe5a1eb62
commit 71404a7372
1 changed files with 114 additions and 85 deletions

View File

@ -81,6 +81,7 @@ typedef struct tagStatStruct {
mode_t st_mode;
uid_t st_uid;
gid_t st_gid;
SFGAOF sfAttr;
} StatStruct;
/* UnixFolder object layout and typedef.
@ -110,70 +111,17 @@ typedef struct _UnixFolder {
* FALSE, otherwise
*/
static inline BOOL UNIXFS_is_pidl_of_type(LPITEMIDLIST pIDL, SHCONTF fFilter) {
LPSTR pszText = _ILGetTextPointer(pIDL);
if (!pszText) return FALSE;
if (pszText[0] == '.' && !(fFilter & SHCONTF_INCLUDEHIDDEN)) return FALSE;
LPPIDLDATA pIDLData = _ILGetDataPointer(pIDL);
if (!(fFilter & SHCONTF_INCLUDEHIDDEN) && pIDLData &&
(pIDLData->u.file.uFileAttribs & FILE_ATTRIBUTE_HIDDEN))
{
return FALSE;
}
if (_ILIsFolder(pIDL) && (fFilter & SHCONTF_FOLDERS)) return TRUE;
if (_ILIsValue(pIDL) && (fFilter & SHCONTF_NONFOLDERS)) return TRUE;
return FALSE;
}
/******************************************************************************
* UNIXFS_build_shitemid [Internal]
*
* Constructs a new SHITEMID for a single path item (up to the next '/' or
* '\0') into a buffer. Decorates the SHITEMID with information from a stat
* system call.
*
* PARAMS
* name [I] The name of the next path item. Terminated by either '\0' or '/'.
* pStat [I] A stat struct variable obtained by a stat system call on the file.
* buffer [O] SHITEMID will be constructed here.
*
* RETURNS
* A pointer to the next '/' or '\0' character in name.
*
* NOTES
* Minimum size of buffer is SHITEMID_LEN_FROM_NAME_LEN(strlen(name)).
* If what you need is a PIDLLIST with a single SHITEMID, don't forget to append
* a 0 USHORT value.
*/
static char* UNIXFS_build_shitemid(char *name, struct stat *pStat, void *buffer) {
LARGE_INTEGER time;
FILETIME fileTime;
LPPIDLDATA pIDLData;
StatStruct *pStatStruct;
int cNameLen;
char *pSlash;
TRACE("(name=%s, pStat=%p, buffer=%p)\n", debugstr_a(name), pStat, buffer);
pSlash = strchr(name, '/');
cNameLen = pSlash ? pSlash - name : strlen(name);
memset(buffer, 0, SHITEMID_LEN_FROM_NAME_LEN(cNameLen));
((LPSHITEMID)buffer)->cb = SHITEMID_LEN_FROM_NAME_LEN(cNameLen) ;
pIDLData = _ILGetDataPointer((LPCITEMIDLIST)buffer);
pIDLData->type = S_ISDIR(pStat->st_mode) ? PT_FOLDER : PT_VALUE;
pIDLData->u.file.dwFileSize = (DWORD)pStat->st_size;
RtlSecondsSince1970ToTime( pStat->st_mtime, &time );
fileTime.dwLowDateTime = time.u.LowPart;
fileTime.dwHighDateTime = time.u.HighPart;
FileTimeToDosDateTime(&fileTime, &pIDLData->u.file.uFileDate, &pIDLData->u.file.uFileTime);
pIDLData->u.file.uFileAttribs =
(S_ISDIR(pStat->st_mode) ? FILE_ATTRIBUTE_DIRECTORY : 0) |
(name[0] == '.' ? FILE_ATTRIBUTE_HIDDEN : 0);
memcpy(pIDLData->u.file.szNames, name, cNameLen);
pStatStruct = LPSTATSTRUCT_FROM_LPSHITEMID(buffer);
pStatStruct->st_mode = pStat->st_mode;
pStatStruct->st_uid = pStat->st_uid;
pStatStruct->st_gid = pStat->st_gid;
return pSlash ? pSlash+1 : (name + cNameLen);
}
/******************************************************************************
* UNIXFS_get_unix_path [Internal]
*
@ -297,6 +245,99 @@ static BOOL UNIXFS_get_unix_path(LPCWSTR pszDosPath, char *pszCanonicalPath)
return TRUE;
}
/******************************************************************************
* UNIXFS_build_shitemid [Internal]
*
* Constructs a new SHITEMID for the last component of path 'pszUnixPath' into
* buffer 'pIDL'. Decorates the SHITEMID with information from a stat system call.
*
* PARAMS
* pszUnixPath [I] An absolute path. The SHITEMID will be build for the last component.
* pIDL [O] SHITEMID will be constructed here.
*
* RETURNS
* Success: A pointer to the terminating '\0' character of path.
* Failure: NULL
*
* NOTES
* Minimum size of pIDL is SHITEMID_LEN_FROM_NAME_LEN(strlen(last_component_of_path)).
* If what you need is a PIDLLIST with a single SHITEMID, don't forget to append
* a 0 USHORT value.
*/
static char* UNIXFS_build_shitemid(char *pszUnixPath, void *pIDL) {
LARGE_INTEGER time;
FILETIME fileTime;
LPPIDLDATA pIDLData;
struct stat fileStat;
StatStruct *pStatStruct;
char szDevicePath[FILENAME_MAX], *pszComponent;
int cComponentLen, cUnixLen = strlen(pszUnixPath);
DWORD dwDrivemap = GetLogicalDrives();
WCHAR wszDosDevice[4] = { 'A', ':', '\\', 0 };
TRACE("(pszUnixPath=%s, pIDL=%p)\n", debugstr_a(pszUnixPath), pIDL);
/* Compute the SHITEMID's length and wipe it. */
pszComponent = strrchr(pszUnixPath, '/') + 1;
cComponentLen = strlen(pszComponent);
memset(pIDL, 0, SHITEMID_LEN_FROM_NAME_LEN(cComponentLen));
((LPSHITEMID)pIDL)->cb = SHITEMID_LEN_FROM_NAME_LEN(cComponentLen) ;
/* We are only interested in regular files and directories. */
if (stat(pszUnixPath, &fileStat)) return NULL;
if (!S_ISDIR(fileStat.st_mode) && !S_ISREG(fileStat.st_mode)) return NULL;
pStatStruct = LPSTATSTRUCT_FROM_LPSHITEMID(pIDL);
pStatStruct->st_mode = fileStat.st_mode;
pStatStruct->st_uid = fileStat.st_uid;
pStatStruct->st_gid = fileStat.st_gid;
pStatStruct->sfAttr = S_ISDIR(fileStat.st_mode) ? (SFGAO_FOLDER|SFGAO_HASSUBFOLDER) : 0;
/* Determine the correct FILESYSANCESTOR and FILESYSTEM flags.
* FIXME: This needs caching of the canonicalized unix paths to speed it up. */
while (wszDosDevice[0] <= 'Z') {
if (dwDrivemap & 0x1) {
if (UNIXFS_get_unix_path(wszDosDevice, szDevicePath)) {
int cDeviceLen = strlen(szDevicePath);
if (cUnixLen < cDeviceLen) {
/* If the unix path is a prefix of any device path,
* then it's an filesystem ancestor. */
if (S_ISDIR(fileStat.st_mode) &&
!strncmp(pszUnixPath, szDevicePath, cUnixLen))
{
pStatStruct->sfAttr |= SFGAO_FILESYSANCESTOR;
}
} else {
/* If any device path is a prefix of the unix path,
* then the unix path is within the filesystem. */
if (!strncmp(pszUnixPath, szDevicePath, cDeviceLen))
pStatStruct->sfAttr |= SFGAO_FILESYSTEM;
}
}
}
dwDrivemap >>= 1;
wszDosDevice[0]++;
}
/* Set shell32's standard SHITEMID data fields. */
pIDLData = _ILGetDataPointer((LPCITEMIDLIST)pIDL);
pIDLData->type = S_ISDIR(fileStat.st_mode) ? PT_FOLDER : PT_VALUE;
pIDLData->u.file.dwFileSize = (DWORD)fileStat.st_size;
RtlSecondsSince1970ToTime( fileStat.st_mtime, &time );
fileTime.dwLowDateTime = time.u.LowPart;
fileTime.dwHighDateTime = time.u.HighPart;
FileTimeToDosDateTime(&fileTime, &pIDLData->u.file.uFileDate, &pIDLData->u.file.uFileTime);
pIDLData->u.file.uFileAttribs = 0;
if (S_ISDIR(fileStat.st_mode)) pIDLData->u.file.uFileAttribs |= FILE_ATTRIBUTE_DIRECTORY;
if (pszComponent[0] == '.' && !(pStatStruct->sfAttr & SFGAO_FILESYSANCESTOR))
/* Don't hide fs ancestors (e.g. the .wine in /home/fubar/.wine/drive_c) */
pIDLData->u.file.uFileAttribs |= FILE_ATTRIBUTE_HIDDEN;
memcpy(pIDLData->u.file.szNames, pszComponent, cComponentLen);
return pszComponent + cComponentLen;
}
/******************************************************************************
* UNIXFS_path_to_pidl [Internal]
*
@ -314,8 +355,7 @@ static BOOL UNIXFS_get_unix_path(LPCWSTR pszDosPath, char *pszCanonicalPath)
*/
static BOOL UNIXFS_path_to_pidl(UnixFolder *pUnixFolder, const WCHAR *path, LPITEMIDLIST *ppidl) {
LPITEMIDLIST pidl;
struct stat fileStat;
int cSubDirs, cPidlLen, res, cPathLen;
int cSubDirs, cPidlLen, cPathLen;
char *pSlash, szCompletePath[FILENAME_MAX], *pNextPathElement;
TRACE("pUnixFolder=%p, path=%s, ppidl=%p\n", pUnixFolder, debugstr_w(path), ppidl);
@ -381,22 +421,14 @@ static BOOL UNIXFS_path_to_pidl(UnixFolder *pUnixFolder, const WCHAR *path, LPIT
/* Concatenate the SHITEMIDs of the sub-directories. */
while (*pNextPathElement) {
pSlash = strchr(pNextPathElement, '/');
if (pSlash) {
*pSlash = '\0';
res = stat(szCompletePath, &fileStat);
*pSlash = '/';
if (res) {
SHFree(pidl);
return FALSE;
}
} else {
if (stat(szCompletePath, &fileStat)) {
SHFree(pidl);
return FALSE;
}
if (pSlash) *pSlash = '\0';
pNextPathElement = UNIXFS_build_shitemid(szCompletePath, pidl);
if (pSlash) *pSlash = '/';
if (!pNextPathElement) {
SHFree(pidl);
return FALSE;
}
pNextPathElement = UNIXFS_build_shitemid(pNextPathElement, &fileStat, pidl);
pidl = ILGetNext(pidl);
}
pidl->mkid.cb = 0; /* Terminate the ITEMIDLIST */
@ -560,8 +592,6 @@ static BOOL UNIXFS_build_subfolder_pidls(UnixFolder *pUnixFolder)
if (!strcmp(pDirEntry->d_name, ".") || !strcmp(pDirEntry->d_name, "..")) continue;
sprintf(pszFQPath, "%s%s", pUnixFolder->m_pszPath, pDirEntry->d_name);
if (stat(pszFQPath, &fileStat)) continue;
if (!S_ISDIR(fileStat.st_mode) && !S_ISREG(fileStat.st_mode)) continue;
sLen = strlen(pDirEntry->d_name);
pid = (LPSHITEMID)SHAlloc(SHITEMID_LEN_FROM_NAME_LEN(sLen)+sizeof(USHORT));
@ -569,7 +599,10 @@ static BOOL UNIXFS_build_subfolder_pidls(UnixFolder *pUnixFolder)
WARN("SHAlloc failed!\n");
return FALSE;
}
UNIXFS_build_shitemid(pDirEntry->d_name, &fileStat, pid);
if (!UNIXFS_build_shitemid(pszFQPath, pid)) {
SHFree(pid);
continue;
}
memset(((PBYTE)pid)+pid->cb, 0, sizeof(USHORT));
pUnixFolder->m_apidlSubDirs[i++] = (LPITEMIDLIST)pid;
@ -818,12 +851,8 @@ static HRESULT WINAPI UnixFolder_IShellFolder2_GetAttributesOf(IShellFolder2* if
TRACE("(iface=%p, cidl=%u, apidl=%p, rgfInOut=%p) semi-stub\n", iface, cidl, apidl, rgfInOut);
for (i=0; i<cidl; i++) {
LPPIDLDATA pData = _ILGetDataPointer(apidl[i]);
if (!pData) continue;
if (pData->type == PT_FOLDER) flags &= (SFGAO_FILESYSTEM|SFGAO_FILESYSANCESTOR|SFGAO_FOLDER|SFGAO_HASSUBFOLDER);
if (pData->type == PT_VALUE) flags &= SFGAO_FILESYSTEM;
}
for (i=0; i<cidl; i++)
flags &= LPSTATSTRUCT_FROM_LPSHITEMID(apidl[i])->sfAttr;
*rgfInOut = *rgfInOut & flags;