ft: report a failed extra-file hashing instead of dropping it

ftExtraList::hashAFile() only had a success path: when RsDirUtil::hashFile()
returned false the file was simply forgotten -- not recorded, no event, not even
a log line. Every caller is then left waiting for a hash that will never come,
since the file never enters mHashedList and ExtraFileStatus() keeps answering
"not ready" forever. The web UI attach dialog turns that into a spinner that
cannot be dismissed and one /rsFiles/ExtraFileStatus per second for the rest of
the session.

hashExtraFile() already refuses missing paths and directories, so reaching the
failure means the file was there and still could not be read: permissions, a
share unmounted or a file renamed between the check and this thread, an I/O
error, or the hashing thread being stopped.

Adds RsSharedDirectoriesEventCode::EXTRA_LIST_FILE_HASH_FAILED, carrying the
path in the mFilePath field the event already has -- whose comment on mFileHash,
"null if error occurred", shows the case was meant to exist. The success event
now fills mFilePath and mFileHash too, so a listener can tell which file it is
about instead of re-reading the whole extra list.

While here, the event is posted outside extMutex rather than under it: posting
while holding a service lock invites a deadlock through a handler.
This commit is contained in:
jolavillette 2026-08-16 17:43:20 +02:00
parent 339c765235
commit f4d1de031f
2 changed files with 43 additions and 11 deletions

View File

@ -32,6 +32,7 @@
#include <retroshare/rsfiles.h>
#include "ft/ftextralist.h"
#include "rsitems/rsconfigitems.h"
#include "util/rsdebug.h"
#include "util/rsdir.h"
#include "util/rstime.h"
#include <stdio.h>
@ -99,20 +100,50 @@ void ftExtraList::hashAFile()
details.info.path, details.info.fname, details.info.hash,
details.info.size ))
{
RS_STACK_MUTEX(extMutex);
{
RS_STACK_MUTEX(extMutex);
/* stick it in the available queue */
mFiles[details.info.hash] = details;
mHashOfHash[makeEncryptedHash(details.info.hash)] = details.info.hash;
/* stick it in the available queue */
mFiles[details.info.hash] = details;
mHashOfHash[makeEncryptedHash(details.info.hash)] = details.info.hash;
/* add to the path->hash map */
mHashedList[details.info.path] = details.info.hash;
IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_NOW);
/* add to the path->hash map */
mHashedList[details.info.path] = details.info.hash;
auto ev = std::make_shared<RsSharedDirectoriesEvent>();
ev->mEventCode = RsSharedDirectoriesEventCode::EXTRA_LIST_FILE_ADDED;
rsEvents->postEvent(ev);
IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_NOW);
}
if(rsEvents)
{
auto ev = std::make_shared<RsSharedDirectoriesEvent>();
ev->mEventCode = RsSharedDirectoriesEventCode::EXTRA_LIST_FILE_ADDED;
ev->mFilePath = details.info.path;
ev->mFileHash = details.info.hash;
rsEvents->postEvent(ev);
}
}
else
{
/* hashExtraFile() has already refused the paths that do not exist and
* the directories, so reaching here means the file was there and could
* still not be read: permissions, a share unmounted or a file renamed
* between the two, an I/O error, or this thread being stopped.
*
* Failing silently leaves every caller waiting for a hash that will
* never come -- the file never enters mHashedList, so ExtraFileStatus()
* keeps answering "not ready" forever, and the web UI attach dialog
* polls it once a second for the rest of the session. */
RsErr() << __PRETTY_FUNCTION__ << " failed to hash " << details.info.path
<< ", it will not be added to the extra list" << std::endl;
if(rsEvents)
{
auto ev = std::make_shared<RsSharedDirectoriesEvent>();
ev->mEventCode =
RsSharedDirectoriesEventCode::EXTRA_LIST_FILE_HASH_FAILED;
ev->mFilePath = details.info.path;
rsEvents->postEvent(ev);
}
}
}

View File

@ -192,6 +192,7 @@ enum class RsSharedDirectoriesEventCode: uint8_t {
FRIEND_DIR_LIST_UPDATED = 0x0b, // NOTIFY_LIST_DIRLIST_FRIENDS, friend dir list has been updated
OWN_DIR_LIST_UPDATED = 0x0c, // NOTIFY_LIST_DIRLIST_LOCAL , own dir list has been updated
OWN_DIR_LIST_PROCESSING = 0x0d, // NOTIFY_LIST_DIRLIST_LOCAL prechange
EXTRA_LIST_FILE_HASH_FAILED = 0x0e, // mFilePath: file that could not be hashed, mFileHash null
};
enum class RsFileTransferEventCode: uint8_t {