unixfs: Fix SetNameOf.
Ensure that pidls passed to SHNotify are absolute SetNameOf should fail on absolute path names. Some tests to show this.
This commit is contained in:
parent
1616f81d00
commit
f87efbd14e
|
@ -1216,50 +1216,54 @@ static HRESULT WINAPI UnixFolder_IShellFolder2_GetDisplayNameOf(IShellFolder2* i
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI UnixFolder_IShellFolder2_SetNameOf(IShellFolder2* iface, HWND hwnd,
|
static HRESULT WINAPI UnixFolder_IShellFolder2_SetNameOf(IShellFolder2* iface, HWND hwnd,
|
||||||
LPCITEMIDLIST pidl, LPCOLESTR lpszName, SHGDNF uFlags, LPITEMIDLIST* ppidlOut)
|
LPCITEMIDLIST pidl, LPCOLESTR lpcwszName, SHGDNF uFlags, LPITEMIDLIST* ppidlOut)
|
||||||
{
|
{
|
||||||
UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
|
UnixFolder *This = ADJUST_THIS(UnixFolder, IShellFolder2, iface);
|
||||||
|
|
||||||
|
static const WCHAR awcInvalidChars[] = { '\\', '/', ':', '*', '?', '"', '<', '>', '|' };
|
||||||
char szSrc[FILENAME_MAX], szDest[FILENAME_MAX];
|
char szSrc[FILENAME_MAX], szDest[FILENAME_MAX];
|
||||||
WCHAR *pwszDosDest;
|
WCHAR wszSrcRelative[MAX_PATH];
|
||||||
int cBasePathLen = lstrlenA(This->m_pszPath);
|
int cBasePathLen = lstrlenA(This->m_pszPath), i;
|
||||||
struct stat statDest;
|
struct stat statDest;
|
||||||
LPITEMIDLIST pidlSrc, pidlDest;
|
LPITEMIDLIST pidlSrc, pidlDest, pidlRelativeDest;
|
||||||
|
LPOLESTR lpwszName;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("(iface=%p, hwnd=%p, pidl=%p, lpszName=%s, uFlags=0x%08lx, ppidlOut=%p)\n",
|
TRACE("(iface=%p, hwnd=%p, pidl=%p, lpcwszName=%s, uFlags=0x%08lx, ppidlOut=%p)\n",
|
||||||
iface, hwnd, pidl, debugstr_w(lpszName), uFlags, ppidlOut);
|
iface, hwnd, pidl, debugstr_w(lpcwszName), uFlags, ppidlOut);
|
||||||
|
|
||||||
/* pidl has to contain a single non-empty SHITEMID */
|
/* prepare to fail */
|
||||||
if (_ILIsDesktop(pidl) || !_ILIsPidlSimple(pidl) || !_ILGetTextPointer(pidl))
|
|
||||||
return E_INVALIDARG;
|
|
||||||
|
|
||||||
if (ppidlOut)
|
if (ppidlOut)
|
||||||
*ppidlOut = NULL;
|
*ppidlOut = NULL;
|
||||||
|
|
||||||
|
/* pidl has to contain a single non-empty SHITEMID */
|
||||||
|
if (_ILIsDesktop(pidl) || !_ILIsPidlSimple(pidl) || !_ILGetTextPointer(pidl))
|
||||||
|
return E_INVALIDARG;
|
||||||
|
|
||||||
|
/* check for invalid characters in lpcwszName. */
|
||||||
|
for (i=0; i < sizeof(awcInvalidChars)/sizeof(*awcInvalidChars); i++)
|
||||||
|
if (StrChrW(lpcwszName, awcInvalidChars[i]))
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
||||||
|
|
||||||
/* build source path */
|
/* build source path */
|
||||||
memcpy(szSrc, This->m_pszPath, cBasePathLen);
|
memcpy(szSrc, This->m_pszPath, cBasePathLen);
|
||||||
UNIXFS_filename_from_shitemid(pidl, szSrc + cBasePathLen);
|
UNIXFS_filename_from_shitemid(pidl, szSrc + cBasePathLen);
|
||||||
|
|
||||||
/* build destination path */
|
/* build destination path */
|
||||||
if (uFlags & SHGDN_FORPARSING) { /* absolute path in lpszName */
|
memcpy(szDest, This->m_pszPath, cBasePathLen);
|
||||||
WideCharToMultiByte(CP_UNIXCP, 0, lpszName, -1, szDest, FILENAME_MAX, NULL, NULL);
|
WideCharToMultiByte(CP_UNIXCP, 0, lpcwszName, -1, szDest+cBasePathLen,
|
||||||
} else {
|
FILENAME_MAX-cBasePathLen, NULL, NULL);
|
||||||
WCHAR wszSrcRelative[MAX_PATH];
|
|
||||||
memcpy(szDest, This->m_pszPath, cBasePathLen);
|
|
||||||
WideCharToMultiByte(CP_UNIXCP, 0, lpszName, -1, szDest+cBasePathLen,
|
|
||||||
FILENAME_MAX-cBasePathLen, NULL, NULL);
|
|
||||||
|
|
||||||
/* uFlags is SHGDN_FOREDITING of SHGDN_FORADDRESSBAR. If the filename's
|
/* If the filename's extension is hidden to the user, we have to append it. */
|
||||||
* extension is hidden to the user, we have to append it. */
|
if (!(uFlags & SHGDN_FORPARSING) &&
|
||||||
if (_ILSimpleGetTextW(pidl, wszSrcRelative, MAX_PATH) &&
|
_ILSimpleGetTextW(pidl, wszSrcRelative, MAX_PATH) &&
|
||||||
SHELL_FS_HideExtension(wszSrcRelative))
|
SHELL_FS_HideExtension(wszSrcRelative))
|
||||||
{
|
{
|
||||||
WCHAR *pwszExt = PathFindExtensionW(wszSrcRelative);
|
WCHAR *pwszExt = PathFindExtensionW(wszSrcRelative);
|
||||||
int cLenDest = strlen(szDest);
|
int cLenDest = strlen(szDest);
|
||||||
WideCharToMultiByte(CP_UNIXCP, 0, pwszExt, -1, szDest + cLenDest,
|
WideCharToMultiByte(CP_UNIXCP, 0, pwszExt, -1, szDest + cLenDest,
|
||||||
FILENAME_MAX - cLenDest, NULL, NULL);
|
FILENAME_MAX - cLenDest, NULL, NULL);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("src=%s dest=%s\n", szSrc, szDest);
|
TRACE("src=%s dest=%s\n", szSrc, szDest);
|
||||||
|
|
||||||
|
@ -1272,36 +1276,30 @@ static HRESULT WINAPI UnixFolder_IShellFolder2_SetNameOf(IShellFolder2* iface, H
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
/* Build a pidl for the path of the renamed file */
|
/* Build a pidl for the path of the renamed file */
|
||||||
if (This->m_dwPathMode == PATHMODE_DOS)
|
lpwszName = SHAlloc((lstrlenW(lpcwszName)+1)*sizeof(WCHAR)); /* due to const correctness. */
|
||||||
{
|
lstrcpyW(lpwszName, lpcwszName);
|
||||||
pwszDosDest = wine_get_dos_file_name(szDest);
|
hr = IShellFolder2_ParseDisplayName(iface, NULL, NULL, lpwszName, NULL, &pidlRelativeDest, NULL);
|
||||||
}
|
SHFree(lpwszName);
|
||||||
else
|
if (FAILED(hr)) {
|
||||||
{
|
|
||||||
int len = MultiByteToWideChar(CP_UNIXCP, 0, szDest, -1, NULL, 0);
|
|
||||||
|
|
||||||
pwszDosDest = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
||||||
MultiByteToWideChar(CP_UNIXCP, 0, szDest, -1, pwszDosDest, len);
|
|
||||||
}
|
|
||||||
if (!pwszDosDest || !UNIXFS_path_to_pidl(This, pwszDosDest, &pidlDest)) {
|
|
||||||
HeapFree(GetProcessHeap(), 0, pwszDosDest);
|
|
||||||
rename(szDest, szSrc); /* Undo the renaming */
|
rename(szDest, szSrc); /* Undo the renaming */
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
pidlDest = ILCombine(This->m_pidlLocation, pidlRelativeDest);
|
||||||
|
ILFree(pidlRelativeDest);
|
||||||
|
pidlSrc = ILCombine(This->m_pidlLocation, pidl);
|
||||||
|
|
||||||
/* Inform the shell */
|
/* Inform the shell */
|
||||||
pidlSrc = ILCombine(This->m_pidlLocation, pidl);
|
|
||||||
if (_ILIsFolder(ILFindLastID(pidlDest)))
|
if (_ILIsFolder(ILFindLastID(pidlDest)))
|
||||||
SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_IDLIST, pidlSrc, pidlDest);
|
SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_IDLIST, pidlSrc, pidlDest);
|
||||||
else
|
else
|
||||||
SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_IDLIST, pidlSrc, pidlDest);
|
SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_IDLIST, pidlSrc, pidlDest);
|
||||||
|
|
||||||
|
if (ppidlOut)
|
||||||
|
*ppidlOut = ILClone(ILFindLastID(pidlDest));
|
||||||
|
|
||||||
ILFree(pidlSrc);
|
ILFree(pidlSrc);
|
||||||
ILFree(pidlDest);
|
ILFree(pidlDest);
|
||||||
|
|
||||||
if (ppidlOut)
|
|
||||||
_ILCreateFromPathW(pwszDosDest, ppidlOut);
|
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, pwszDosDest);
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -383,6 +383,35 @@ static void test_GetDisplayName(void)
|
||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
IShellFolder_Release(psfFile);
|
IShellFolder_Release(psfFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Some tests for IShellFolder::SetNameOf */
|
||||||
|
hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
|
||||||
|
ok(SUCCEEDED(hr), "SHBindToParent failed! hr = %08lx\n", hr);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
/* It's ok to use this fixed path. Call will fail anyway. */
|
||||||
|
WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
|
||||||
|
LPITEMIDLIST pidlNew;
|
||||||
|
|
||||||
|
/* The pidl returned through the last parameter of SetNameOf is a simple one. */
|
||||||
|
hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
|
||||||
|
ok (SUCCEEDED(hr), "SetNameOf failed! hr = %08lx\n", hr);
|
||||||
|
ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
|
||||||
|
"pidl returned from SetNameOf should be simple!\n");
|
||||||
|
|
||||||
|
/* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
|
||||||
|
* is implemented on top of SHFileOperation in WinXP. */
|
||||||
|
hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
|
||||||
|
SHGDN_FORPARSING, NULL);
|
||||||
|
ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08lx\n", hr);
|
||||||
|
|
||||||
|
/* Rename the file back to it's original name. SetNameOf ignores the fact, that the
|
||||||
|
* SHGDN flags specify an absolute path. */
|
||||||
|
hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
|
||||||
|
ok (SUCCEEDED(hr), "SetNameOf failed! hr = %08lx\n", hr);
|
||||||
|
|
||||||
|
ILFree(pidlNew);
|
||||||
|
IShellFolder_Release(psfPersonal);
|
||||||
|
}
|
||||||
|
|
||||||
/* Deleting the file and the directory */
|
/* Deleting the file and the directory */
|
||||||
DeleteFileA(szTestFile);
|
DeleteFileA(szTestFile);
|
||||||
|
|
Loading…
Reference in New Issue