-
Notifications
You must be signed in to change notification settings - Fork 37
Fix: [smb] Compressed file seek detection #317
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix: [smb] Compressed file seek detection #317
Conversation
-- Compressed file seek detection Log: fix issue Bug: Bug: https://pms.uniontech.com/bug-view-278613.html
Reviewer's GuideThis PR introduces a file‐seek support check for compressed archives by adding a new utility function, integrating early‐fail seek detection into CLI and plugin operations, and extending the UI to surface a dedicated file‐seek error. Sequence diagram for early seek support check in archive operationssequenceDiagram
participant "CliInterface"
participant "Common"
participant "MainWindow"
participant "User"
User->>"CliInterface": Initiate archive operation (list/extract/add)
"CliInterface"->>"Common": isSupportSeek(m_strArchiveName)
"Common"-->>"CliInterface": true/false
alt Seek not supported
"CliInterface"->>"MainWindow": Emit error ET_FileSeekError
"MainWindow"->>"User": Show error message (EI_FileSeekError)
end
Class diagram for updated Common class and error enumsclassDiagram
class Common {
+bool isSupportSeek(QString sFileName)
+bool isSubpathOfDlnfs(const QString &path)
+QString handleLongNameforPath(...)
-bool findDlnfsPath(...)
}
class ErrorType {
ET_UserCancelOpertion
ET_ExistVolume
ET_FileSeekError
}
class ErrorInfo {
EI_InsufficientDiskSpace
EI_ArchiveNoData
EI_ExistVolume
EI_FileSeekError
}
Common --> ErrorType
Common --> ErrorInfo
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
deepin pr auto review我来对这段代码进行审查分析:
a) bool Common::isSupportSeek(QString sFileName)
{
QFileInfo info(sFileName);
if(info.exists()) {
// ... 文件存在时的处理
} else {
// 文件不存在时创建临时文件测试
QString tempDir = info.absoluteDir().path();
QString fileTemplate = tempDir + "/tempfile_XXXXXX";
QTemporaryFile tempFile(fileTemplate);
// ...
}
}问题:
建议改进: bool Common::isSupportSeek(const QString &sFileName)
{
// 直接检查目标路径所在的文件系统
QFileInfo info(sFileName);
QString path = info.exists() ? sFileName : info.absolutePath();
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
return false;
}
bool canSeek = file.seek(0);
file.close();
return canSeek;
}b) 错误处理不一致: // 在 extractFiles 中
return PFT_Nomral; // 拼写错误且返回值不匹配
// 在其他地方
return PFT_Error; // 正确的错误返回值建议:
c) 代码重复: if (!m_common->isSupportSeek(m_strArchiveName)) {
// 相同的错误处理代码
}建议:
d) 性能优化: QTimer::singleShot(1000, this, [=]() {
// 错误处理
});问题:
建议:
e) 安全性问题:
a) 添加详细的错误日志: qDebug() << "Seek operation not supported for file:" << sFileName;b) 考虑添加缓存机制,避免重复检查同一文件系统 c) 添加单元测试覆盖各种场景:
d) 文档完善:
这些修改将提高代码的健壮性、性能和可维护性。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `3rdparty/interface/common.cpp:474` </location>
<code_context>
+ tempFile.flush();
+ }
+ tempFile.close();
+ QString sFileName = tempFile.fileName();
+ QFile file(sFileName);
+ if(file.open(QIODevice::ReadOnly)) {
</code_context>
<issue_to_address>
**nitpick:** Variable shadowing of sFileName may cause confusion.
Consider renaming the inner 'sFileName' variable to avoid shadowing the function parameter and improve code clarity.
</issue_to_address>
### Comment 2
<location> `3rdparty/interface/archiveinterface/cliinterface.cpp:110` </location>
<code_context>
+ emit signalprogress(100);
+ emit signalFinished(PFT_Error);
+ });
+ return PFT_Nomral;
+ }
+
</code_context>
<issue_to_address>
**issue (typo):** Typo in return value: 'PFT_Nomral' should be 'PFT_Normal'.
Please update the return value to 'PFT_Normal' to ensure correctness.
```suggestion
+ return PFT_Normal;
```
</issue_to_address>
### Comment 3
<location> `3rdparty/interface/common.cpp:449` </location>
<code_context>
});
}
+bool Common::isSupportSeek(QString sFileName)
+{
+ QFileInfo info(sFileName);
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting the file open/seek logic into a helper function to eliminate duplication and clarify intent.
```suggestion
Extract the “open-and-seek” logic into a small helper, then collapse the two branches into a single flow. For example:
```cpp
// Common.h
class Common {
…
static bool trySeekFile(const QString& path);
bool isSupportSeek(const QString& sFileName);
};
// Common.cpp
bool Common::trySeekFile(const QString& path)
{
QFile file(path);
if (!file.open(QIODevice::ReadOnly))
return false;
bool ok = file.seek(0);
file.close();
return ok;
}
bool Common::isSupportSeek(const QString& sFileName)
{
QFileInfo info(sFileName);
if (info.exists()) {
return trySeekFile(sFileName);
}
// Create a temp file in the same directory
QString templatePath = info.absoluteDir().filePath("tempfile_XXXXXX");
QTemporaryFile tempFile(templatePath);
tempFile.setAutoRemove(true);
if (!tempFile.open())
return false;
tempFile.write("test\n");
tempFile.close();
return trySeekFile(tempFile.fileName());
}
```
Benefits:
- No duplicate open/seek/close
- Single return points for each branch
- Clear intent in `trySeekFile`
```
</issue_to_address>
### Comment 4
<location> `3rdparty/interface/archiveinterface/cliinterface.cpp:78` </location>
<code_context>
m_workStatus = WT_List;
+ // 是否支持seek
+ if(!m_common->isSupportSeek(m_strArchiveName)) {
+ QTimer::singleShot(1000, this, [=]() {
+ m_eErrorType = ET_FileSeekError;
</code_context>
<issue_to_address>
**issue (complexity):** Consider refactoring the repeated QTimer error-handling code into a helper function and macro to reduce duplication.
Here’s one way to collapse those three identical QTimer blocks into a single helper + guard macro. This preserves your exact return-values but only writes the “error timer” code once.
```cpp
// In CliInterface.h (or a common private section)
private:
void emitSeekErrorAndFinish() {
QTimer::singleShot(1000, this, [this]() {
m_eErrorType = ET_FileSeekError;
emit signalprogress(100);
emit signalFinished(PFT_Error);
});
}
#define RETURN_IF_NO_SEEK(retval) \
do { \
if (!m_common->isSupportSeek(m_strArchiveName)) { \
emitSeekErrorAndFinish(); \
return retval; \
} \
} while (0)
```
Then your three methods collapse to:
```cpp
PluginFinishType CliInterface::list() {
setPassword(QString());
DataManager::get_instance().resetArchiveData();
m_setHasRootDirs.clear();
m_setHasHandlesDirs.clear();
m_workStatus = WT_List;
RETURN_IF_NO_SEEK(PFT_Error);
bool ret = runProcess( /* … */ );
return ret ? PFT_Nomral : PFT_Error;
}
PluginFinishType CliInterface::extractFiles(...) {
RETURN_IF_NO_SEEK(PFT_Nomral);
// … rest of extractFiles …
}
PluginFinishType CliInterface::addFiles(...) {
// only guard when files not empty
if (!files.isEmpty()) {
RETURN_IF_NO_SEEK(PFT_Nomral);
}
// … rest of addFiles …
}
```
That removes three copies of the QTimer+lambda while keeping every return‐value exactly as before.
</issue_to_address>
### Comment 5
<location> `src/source/mainwindow.cpp:1812` </location>
<code_context>
showErrorMessage(FI_Compress, EI_ExistVolume, true);
break;
+ // ftp目录不支持seek操作
+ case ET_FileSeekError:
+ showErrorMessage(FI_Compress, EI_FileSeekError, true);
+ break;
</code_context>
<issue_to_address>
**issue (complexity):** Consider refactoring repeated ET_FileSeekError/EI_FileSeekError handling into helper functions to avoid code duplication.
```markdown
You’re repeating the same ET_FileSeekError/EI_FileSeekError handling in every switch. You can pull that logic out into one helper per subsystem and early‐return, or at least factor the UI messages into a lookup—then each switch only needs:
1) one `if (eErrorType == ET_FileSeekError) { … }`
2) a normal switch without the duplicated case
Example for the job‐level error→popup section:
```cpp
// new helper at top of file:
bool handleSeekError(ArchiveJob::JobType jt, ErrorType e, bool needsConfirm)
{
if (e != ET_FileSeekError)
return false;
// map job → FI_*
FileInterface fi;
switch (jt) {
case ArchiveJob::JT_Compress: fi = FI_Compress; break;
case ArchiveJob::JT_Load: fi = FI_Load; break;
case ArchiveJob::JT_Extract:
case ArchiveJob::JT_StepExtract: fi = FI_Uncompress; break;
default: fi = FI_Compress; /* fallback */ }
showErrorMessage(fi, EI_FileSeekError, needsConfirm);
return true;
}
// in your outer job switch:
case ArchiveJob::JT_Compress: {
bool needsConfirm = true; // existing logic
if (handleSeekError(m_eJobType, eErrorType, needsConfirm))
break;
switch (eErrorType) {
// … now no ET_FileSeekError here …
}
} break;
```
And for the UI‐mapping you can centralize the detail strings:
```cpp
// helper in .cpp
static QString seekDetail(FileInterface fi) {
switch (fi) {
case FI_Compress:
return tr("No compression support in current directory. Download the files to a local device.");
case FI_Load:
return tr("Can't open compressed packages in current directory. Download the compressed package to a local device.");
case FI_Uncompress:
return tr("No extraction support in current directory. Download the compressed package to a local device.");
default:
return tr("Operation not supported in current directory.");
}
}
// then in your failure‐page switch:
case EI_FileSeekError:
m_pFailurePage->setFailureDetail(seekDetail(currentFI));
break;
```
These two small helpers remove all the repetitive `case ET_FileSeekError` and `case EI_FileSeekError` blocks while keeping your behavior identical.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| tempFile.flush(); | ||
| } | ||
| tempFile.close(); | ||
| QString sFileName = tempFile.fileName(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: Variable shadowing of sFileName may cause confusion.
Consider renaming the inner 'sFileName' variable to avoid shadowing the function parameter and improve code clarity.
| emit signalprogress(100); | ||
| emit signalFinished(PFT_Error); | ||
| }); | ||
| return PFT_Nomral; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (typo): Typo in return value: 'PFT_Nomral' should be 'PFT_Normal'.
Please update the return value to 'PFT_Normal' to ensure correctness.
| return PFT_Nomral; | |
| + return PFT_Normal; |
| m_workStatus = WT_List; | ||
|
|
||
| // 是否支持seek | ||
| if(!m_common->isSupportSeek(m_strArchiveName)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (complexity): Consider refactoring the repeated QTimer error-handling code into a helper function and macro to reduce duplication.
Here’s one way to collapse those three identical QTimer blocks into a single helper + guard macro. This preserves your exact return-values but only writes the “error timer” code once.
// In CliInterface.h (or a common private section)
private:
void emitSeekErrorAndFinish() {
QTimer::singleShot(1000, this, [this]() {
m_eErrorType = ET_FileSeekError;
emit signalprogress(100);
emit signalFinished(PFT_Error);
});
}
#define RETURN_IF_NO_SEEK(retval) \
do { \
if (!m_common->isSupportSeek(m_strArchiveName)) { \
emitSeekErrorAndFinish(); \
return retval; \
} \
} while (0)Then your three methods collapse to:
PluginFinishType CliInterface::list() {
setPassword(QString());
DataManager::get_instance().resetArchiveData();
m_setHasRootDirs.clear();
m_setHasHandlesDirs.clear();
m_workStatus = WT_List;
RETURN_IF_NO_SEEK(PFT_Error);
bool ret = runProcess( /* … */ );
return ret ? PFT_Nomral : PFT_Error;
}
PluginFinishType CliInterface::extractFiles(...) {
RETURN_IF_NO_SEEK(PFT_Nomral);
// … rest of extractFiles …
}
PluginFinishType CliInterface::addFiles(...) {
// only guard when files not empty
if (!files.isEmpty()) {
RETURN_IF_NO_SEEK(PFT_Nomral);
}
// … rest of addFiles …
}That removes three copies of the QTimer+lambda while keeping every return‐value exactly as before.
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: GongHeng2017, lzwind The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
/merge |
-- Compressed file seek detection
Log: fix issue
Bug: Bug: https://pms.uniontech.com/bug-view-278613.html
Summary by Sourcery
Implement filesystem seek support detection and gracefully handle cases where seek is not supported during archive operations
Bug Fixes:
Enhancements: