@@ -18,6 +18,11 @@ RESTORE_COMPILER_WARNINGS
18
18
#include < unistd.h>
19
19
#endif
20
20
21
+ inline static QString getLastFileError ()
22
+ {
23
+ return QString::fromStdString (thin_io::file::text_for_last_error ());
24
+ }
25
+
21
26
static constexpr QFileDevice::FileTime supportedFileTimeTypes[] {
22
27
QFileDevice::FileAccessTime,
23
28
#ifndef __linux__
@@ -30,17 +35,18 @@ static constexpr QFileDevice::FileTime supportedFileTimeTypes[] {
30
35
};
31
36
32
37
// Operations
33
- CFileManipulator::CFileManipulator (CFileSystemObject object) : _object{std::move (object)}
38
+ CFileManipulator::CFileManipulator (const CFileSystemObject& object) :
39
+ _srcObject{ object }
34
40
{
35
41
}
36
42
37
43
FileOperationResultCode CFileManipulator::copyAtomically (const QString& destFolder, const QString& newName, TransferPermissions transferPermissions)
38
44
{
39
- assert_r (_object .isFile ());
45
+ assert_r (_srcObject .isFile ());
40
46
assert_r (QFileInfo{destFolder}.isDir ());
41
47
42
- QFile file (_object .fullAbsolutePath ());
43
- const QString newFilePath = destFolder + (newName.isEmpty () ? _object .fullName () : newName);
48
+ QFile file (_srcObject .fullAbsolutePath ());
49
+ const QString newFilePath = destFolder + (newName.isEmpty () ? _srcObject .fullName () : newName);
44
50
bool succ = file.copy (newFilePath);
45
51
if (succ)
46
52
{
@@ -58,22 +64,22 @@ FileOperationResultCode CFileManipulator::copyAtomically(const QString& destFold
58
64
59
65
FileOperationResultCode CFileManipulator::moveAtomically (const QString& destFolder, const QString& newName, OverwriteExistingFile overwriteExistingFile)
60
66
{
61
- if (!_object .exists ())
67
+ if (!_srcObject .exists ())
62
68
return FileOperationResultCode::ObjectDoesntExist;
63
- else if (_object .isCdUp ())
69
+ else if (_srcObject .isCdUp ())
64
70
return FileOperationResultCode::Fail;
65
71
66
72
assert_debug_only (QFileInfo{ destFolder }.isDir ());
67
- const QString fullNewName = destFolder % ' /' % (newName.isEmpty () ? _object .fullName () : newName);
73
+ const QString fullNewName = destFolder % ' /' % (newName.isEmpty () ? _srcObject .fullName () : newName);
68
74
CFileSystemObject destInfo (fullNewName);
69
- const bool newNameDiffersOnlyInLetterCase = destInfo.fullAbsolutePath ().compare (_object .fullAbsolutePath (), Qt::CaseInsensitive) == 0 ;
75
+ const bool newNameDiffersOnlyInLetterCase = destInfo.fullAbsolutePath ().compare (_srcObject .fullAbsolutePath (), Qt::CaseInsensitive) == 0 ;
70
76
71
77
// If the file system is case-insensitive, and the source and destination only differ by case, renaming is allowed even though formally the destination already exists (fix for #102)
72
78
if ((caseSensitiveFilesystem () || !newNameDiffersOnlyInLetterCase) && destInfo.exists ())
73
79
{
74
- if (_object .isDir ())
80
+ if (_srcObject .isDir ())
75
81
return FileOperationResultCode::TargetAlreadyExists;
76
- else if (overwriteExistingFile == true && _object .isFile () && destInfo.isFile ())
82
+ else if (overwriteExistingFile == true && _srcObject .isFile () && destInfo.isFile ())
77
83
{
78
84
// Special case: it may be allowed to replace the existing file (https://github.com/VioletGiraffe/file-commander/issues/123)
79
85
if (remove (destInfo) != FileOperationResultCode::Ok)
@@ -89,27 +95,27 @@ FileOperationResultCode CFileManipulator::moveAtomically(const QString& destFold
89
95
// Windows: QFile::rename and QDir::rename fail to handle names that only differ by letter case (https://bugreports.qt.io/browse/QTBUG-3570)
90
96
// Also, QFile::rename will attempt to painfully copy the file if it's locked.
91
97
#ifdef _WIN32
92
- if (MoveFileW (reinterpret_cast <const WCHAR*>(_object .fullAbsolutePath ().utf16 ()), reinterpret_cast <const WCHAR*>(destInfo.fullAbsolutePath ().utf16 ())) != 0 )
98
+ if (MoveFileW (reinterpret_cast <const WCHAR*>(_srcObject .fullAbsolutePath ().utf16 ()), reinterpret_cast <const WCHAR*>(destInfo.fullAbsolutePath ().utf16 ())) != 0 )
93
99
return FileOperationResultCode::Ok;
94
100
95
101
_lastErrorMessage = QString::fromStdString (ErrorStringFromLastError ());
96
102
return FileOperationResultCode::Fail;
97
103
#else
98
- if (_object .isFile ())
104
+ if (_srcObject .isFile ())
99
105
{
100
- QFile file (_object .fullAbsolutePath ());
106
+ QFile file (_srcObject .fullAbsolutePath ());
101
107
if (!file.rename (fullNewName))
102
108
{
103
109
_lastErrorMessage = file.errorString ();
104
110
return FileOperationResultCode::Fail;
105
111
}
106
112
107
- _object .refreshInfo (); // TODO: what is this for?
113
+ _srcObject .refreshInfo (); // TODO: what is this for?
108
114
return FileOperationResultCode::Ok;
109
115
}
110
- else if (_object .isDir ())
116
+ else if (_srcObject .isDir ())
111
117
{
112
- return QDir{}.rename (_object .fullAbsolutePath (), fullNewName) ? FileOperationResultCode::Ok : FileOperationResultCode::Fail;
118
+ return QDir{}.rename (_srcObject .fullAbsolutePath (), fullNewName) ? FileOperationResultCode::Ok : FileOperationResultCode::Fail;
113
119
}
114
120
else
115
121
return FileOperationResultCode::Fail;
@@ -132,22 +138,22 @@ FileOperationResultCode CFileManipulator::moveAtomically(const CFileSystemObject
132
138
FileOperationResultCode CFileManipulator::copyChunk (size_t chunkSize, const QString& destFolder, const QString& newName /* = QString()*/ , const bool transferPermissions, const bool transferDates)
133
139
{
134
140
assert_debug_only (bool (_thisFile) == bool (_destFile));
135
- assert_debug_only (_object .isFile ());
141
+ assert_debug_only (_srcObject .isFile ());
136
142
assert_debug_only (QFileInfo (destFolder).isDir ());
137
143
138
144
if (!copyOperationInProgress ())
139
145
{
140
146
_pos = 0 ;
141
147
142
148
// Creating files
143
- _thisFile = std::make_unique<QFile>(_object .fullAbsolutePath ());
144
- _destFile = std::make_unique<QFile>(destFolder + (newName. isEmpty () ? _object. fullName () : newName) );
149
+ _thisFile = std::make_unique<QFile>(_srcObject .fullAbsolutePath ());
150
+ _destFile = std::make_unique<thin_io::file>( );
145
151
146
152
for (const auto fileTimeType: supportedFileTimeTypes)
147
153
_sourceFileTime[fileTimeType] = _thisFile->fileTime (fileTimeType);
148
154
149
155
// Initializing - opening files
150
- if (!_thisFile->open (QFile::ReadOnly))
156
+ if (!_thisFile->open (QFile::ReadOnly | QFile::Unbuffered ))
151
157
{
152
158
_lastErrorMessage = _thisFile->errorString ();
153
159
@@ -157,35 +163,34 @@ FileOperationResultCode CFileManipulator::copyChunk(size_t chunkSize, const QStr
157
163
return FileOperationResultCode::Fail;
158
164
}
159
165
160
- if (!_destFile->open (QFile::ReadWrite))
166
+ _destinationFilePath = destFolder + (newName.isEmpty () ? _srcObject.fullName () : newName);
167
+
168
+ if (!_destFile->open (_destinationFilePath.toUtf8 ().constData (), thin_io::file_definitions::Write))
161
169
{
162
- _lastErrorMessage = _destFile-> errorString ();
170
+ _lastErrorMessage = getLastFileError ();
163
171
164
172
_thisFile.reset ();
165
173
_destFile.reset ();
166
174
167
175
return FileOperationResultCode::Fail;
168
176
}
169
177
170
- if (!_destFile->resize ((qint64)_object .size ()))
171
- {
172
- _lastErrorMessage. clear (); // QFile provides no meaningful message for this case.
173
- _destFile->close ();
174
- assert_r (_destFile-> remove ());
178
+ // if (!_destFile->truncate(_srcObject .size()))
179
+ // {
180
+ // _lastErrorMessage = getLastFileError ();
181
+ // assert_r( _destFile->close() );
182
+ // assert_r(QFile:: remove(_destinationFilePath ));
175
183
176
- _thisFile.reset ();
177
- _destFile.reset ();
178
-
179
- return FileOperationResultCode::NotEnoughSpaceAvailable;
180
- }
181
-
182
- // Store the original file's attributes to later mirror them onto the copy
184
+ // _thisFile.reset();
185
+ // _destFile.reset();
183
186
187
+ // return FileOperationResultCode::NotEnoughSpaceAvailable;
188
+ // }
184
189
}
185
190
186
- assert_r (_destFile->isOpen () == _thisFile->isOpen ());
191
+ assert_r (_destFile->is_open () == _thisFile->isOpen ());
187
192
188
- const auto actualChunkSize = std::min (chunkSize, (size_t )(_object .size () - _pos));
193
+ const auto actualChunkSize = std::min (chunkSize, (size_t )(_srcObject .size () - _pos));
189
194
190
195
if (actualChunkSize != 0 )
191
196
{
@@ -196,45 +201,48 @@ FileOperationResultCode CFileManipulator::copyChunk(size_t chunkSize, const QStr
196
201
return FileOperationResultCode::Fail;
197
202
}
198
203
199
- auto * dest = _destFile->map ((qint64)_pos, (qint64)actualChunkSize);
200
- if (dest == nullptr )
201
- {
202
- _lastErrorMessage = _destFile->errorString ();
203
- return FileOperationResultCode::Fail;
204
- }
205
-
206
- ::memcpy (dest, src, actualChunkSize);
204
+ // TODO: error handling!
205
+ _destFile->write (src, actualChunkSize);
207
206
_pos += actualChunkSize;
208
-
209
- _thisFile->unmap (src);
210
- _destFile-> unmap (dest );
207
+
208
+ [[maybe_unused]] const bool unmapResult = _thisFile->unmap (src);
209
+ assert_debug_only (unmapResult );
211
210
}
212
211
213
212
// TODO: '<=' ?
214
213
if (actualChunkSize < chunkSize)
215
214
{
216
- // Copying complete
217
- if (transferPermissions)
218
- _lastErrorMessage = copyPermissions (*_thisFile, * _destFile);
215
+ // TODO: error handling!
216
+ _destFile-> close ();
217
+ _destFile. reset ( );
219
218
220
- if (transferDates)
219
+ // Copying complete
220
+ if (transferPermissions || transferDates)
221
221
{
222
- // Note: The file must be open to use setFileTime()
223
-
224
- for (const auto fileTimeType: supportedFileTimeTypes)
225
- assert_r (_destFile->setFileTime (_sourceFileTime[fileTimeType], fileTimeType));
222
+ assert_debug_only (!_destinationFilePath.isEmpty ());
223
+ // TODO: this is ineffective; need to support permission and date transfer in thin_io
224
+ QFile qDstFile (_destinationFilePath);
225
+ if (!qDstFile.open (QFile::ReadOnly | QFile::WriteOnly))
226
+ {
227
+ // TODO: error handling!
228
+ }
229
+
230
+ if (transferPermissions)
231
+ _lastErrorMessage = copyPermissions (*_thisFile, qDstFile);
232
+
233
+ if (transferDates)
234
+ {
235
+ // Note: The file must be open to use setFileTime()
236
+
237
+ for (const auto fileTimeType : supportedFileTimeTypes)
238
+ assert_r (qDstFile.setFileTime (_sourceFileTime[fileTimeType], fileTimeType));
239
+ }
226
240
}
227
241
228
242
_thisFile.reset ();
229
- _destFile.reset ();
230
243
231
244
if (transferPermissions && !_lastErrorMessage.isEmpty ())
232
245
return FileOperationResultCode::Fail;
233
-
234
- if (transferDates)
235
- {
236
-
237
- }
238
246
}
239
247
240
248
return FileOperationResultCode::Ok;
@@ -251,7 +259,7 @@ bool CFileManipulator::copyOperationInProgress() const
251
259
return false ;
252
260
253
261
const bool isOpen = _thisFile->isOpen ();
254
- assert_r (isOpen == _destFile->isOpen ());
262
+ assert_r (isOpen == _destFile->is_open ());
255
263
return isOpen;
256
264
}
257
265
@@ -268,18 +276,18 @@ FileOperationResultCode CFileManipulator::cancelCopy()
268
276
_thisFile->close ();
269
277
_destFile->close ();
270
278
271
- const bool succ = _destFile-> remove ( );
279
+ const bool succ = thin_io::file::delete_file (_destinationFilePath. toUtf8 (). constData () );
272
280
_thisFile.reset ();
273
281
_destFile.reset ();
274
282
return succ ? FileOperationResultCode::Ok : FileOperationResultCode::Fail;
275
283
}
276
284
277
285
bool CFileManipulator::makeWritable (bool writable)
278
286
{
279
- assert_and_return_message_r (_object .isFile (), " This method only works for files" , false );
287
+ assert_and_return_message_r (_srcObject .isFile (), " This method only works for files" , false );
280
288
281
289
#ifdef _WIN32
282
- const QString UNCPath = toUncPath (_object .fullAbsolutePath ());
290
+ const QString UNCPath = toUncPath (_srcObject .fullAbsolutePath ());
283
291
const DWORD attributes = GetFileAttributesW (reinterpret_cast <LPCWSTR>(UNCPath.utf16 ()));
284
292
if (attributes == INVALID_FILE_ATTRIBUTES)
285
293
{
@@ -297,7 +305,7 @@ bool CFileManipulator::makeWritable(bool writable)
297
305
#else
298
306
struct stat fileInfo;
299
307
300
- const QByteArray fileName = _object .fullAbsolutePath ().toUtf8 ();
308
+ const QByteArray fileName = _srcObject .fullAbsolutePath ().toUtf8 ();
301
309
if (stat (fileName.constData (), &fileInfo) != 0 )
302
310
{
303
311
_lastErrorMessage = strerror (errno);
@@ -321,11 +329,11 @@ bool CFileManipulator::makeWritable(const CFileSystemObject& object, bool writab
321
329
322
330
FileOperationResultCode CFileManipulator::remove ()
323
331
{
324
- assert_and_return_message_r (_object .exists (), " Object doesn't exist" , FileOperationResultCode::ObjectDoesntExist);
332
+ assert_and_return_message_r (_srcObject .exists (), " Object doesn't exist" , FileOperationResultCode::ObjectDoesntExist);
325
333
326
- if (_object .isFile ())
334
+ if (_srcObject .isFile ())
327
335
{
328
- QFile file (_object .fullAbsolutePath ());
336
+ QFile file (_srcObject .fullAbsolutePath ());
329
337
if (file.remove ())
330
338
return FileOperationResultCode::Ok;
331
339
else
@@ -334,14 +342,14 @@ FileOperationResultCode CFileManipulator::remove()
334
342
return FileOperationResultCode::Fail;
335
343
}
336
344
}
337
- else if (_object .isDir ())
345
+ else if (_srcObject .isDir ())
338
346
{
339
- assert_r (_object .isEmptyDir ());
347
+ assert_r (_srcObject .isEmptyDir ());
340
348
errno = 0 ;
341
- if (!QDir{_object .fullAbsolutePath ()}.rmdir (QStringLiteral (" ." )))
349
+ if (!QDir{_srcObject .fullAbsolutePath ()}.rmdir (QStringLiteral (" ." )))
342
350
{
343
351
#if defined __linux || defined __APPLE__ || defined __FreeBSD__
344
- if (::rmdir (_object .fullAbsolutePath ().toLocal8Bit ().constData ()) == 0 )
352
+ if (::rmdir (_srcObject .fullAbsolutePath ().toLocal8Bit ().constData ()) == 0 )
345
353
return FileOperationResultCode::Ok;
346
354
347
355
_lastErrorMessage = strerror (errno);
0 commit comments