summaryrefslogtreecommitdiff
path: root/plugins/CopyEngine/Ultracopier/ListThread.h
blob: 48e714239b8fae228d0a92c314baf53db14674e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
/** \file ListThread.h
\brief Define the list thread, and management to the action to do
\author alpha_one_x86
\licence GPL3, see the file COPYING */

#ifndef LISTTHREAD_H
#define LISTTHREAD_H

#include <QThread>
#include <QObject>
#include <string>
#include <vector>
#include <unordered_map>
#include <QFileInfo>
#include <QSemaphore>
#include <QTextStream>
#include <QFile>
#include <QTimer>

#include "../../../interface/PluginInterface_CopyEngine.h"
#include "ScanFileOrFolder.h"
#include "TransferThread.h"
#include "MkPath.h"
#include "Environment.h"
#include "DriveManagement.h"

/// \brief Define the list thread, and management to the action to do
class ListThread : public QThread
{
    Q_OBJECT
public:
    explicit ListThread(FacilityInterface * facilityInterface);
    ~ListThread();

    //duplication copy detection
    /** \brief compare the current sources of the copy, with the passed arguments
     * \param sources the sources list to compares with the current sources list
     * \return true if have same sources, else false (or empty) */
    bool haveSameSource(const std::vector<std::string> &sources);
    /** \brief compare the current destination of the copy, with the passed arguments
     * \param destination the destination to compares with the current destination
     * \return true if have same destination, else false (or empty) */
    bool haveSameDestination(const std::string &destination);
    /// \return empty if multiple or no destination
    std::string getUniqueDestinationFolder() const;
    //external soft like file browser have send copy/move list to do
    /** \brief send copy with destination
     * \param sources the sources list to copy
     * \param destination the destination to copy
     * \return true if the copy have been accepted */
    bool newCopy(const std::vector<std::string> &sources,const std::string &destination);
    /** \brief send move without destination, ask the destination
     * \param sources the sources list to move
     * \param destination the destination to move
     * \return true if the move have been accepted */
    bool newMove(const std::vector<std::string> &sources,const std::string &destination);
    /** \brief to set drives detected
     * specific to this copy engine */
    /// \brief to set the collision action
    void setCollisionAction(const FileExistsAction &alwaysDoThisActionForFileExists);
    /** \brief to sync the transfer list
     * Used when the interface is changed, useful to minimize the memory size */
    void syncTransferList();
    /// \brief to store one action to do
    struct ActionToDoTransfer
    {
        uint64_t id;
        uint64_t size;///< Used to set: used in case of transfer or remainingInode for drop folder
        QFileInfo source;///< Used to set: source for transfer, folder to create, folder to drop
        QFileInfo destination;
        Ultracopier::CopyMode mode;
        bool isRunning;///< store if the action si running
        //TransferThread * transfer; // -> see transferThreadList
    };
    std::vector<ActionToDoTransfer> actionToDoListTransfer;
    /// \brief to store one action to do
    struct ActionToDoInode
    {
        ActionType type;///< \see ActionType
        uint64_t id;
        int64_t size;///< Used to set: used in case of transfer or remainingInode for drop folder
        QFileInfo source;///< Keep to copy the right/date, to remove (for move)
        QFileInfo destination;///< Used to set: folder to create, folder to drop
        bool isRunning;///< store if the action si running
    };
    std::vector<ActionToDoInode> actionToDoListInode;
    std::vector<ActionToDoInode> actionToDoListInode_afterTheTransfer;
    int numberOfInodeOperation;
    struct ErrorLogEntry
    {
        QFileInfo source;
        QFileInfo destination;
        std::string error;
        Ultracopier::CopyMode mode;
    };
    std::vector<ErrorLogEntry> errorLog;
    //dir operation thread queue
    MkPath mkPathQueue;
    //to get the return value from copyEngine
    bool getReturnBoolToCopyEngine() const;
    std::pair<quint64,quint64> getReturnPairQuint64ToCopyEngine() const;
    Ultracopier::ItemOfCopyList getReturnItemOfCopyListToCopyEngine() const;

    void set_doChecksum(bool doChecksum);
    void set_checksumIgnoreIfImpossible(bool checksumIgnoreIfImpossible);
    void set_checksumOnlyOnError(bool checksumOnlyOnError);
    void set_osBuffer(bool osBuffer);
    void set_osBufferLimited(bool osBufferLimited);
    void autoStartIfNeeded();
public slots:
    //action on the copy
    /// \brief put the transfer in pause
    void pause();
    /// \brief resume the transfer
    void resume();
    /** \brief skip one transfer entry
     * \param id id of the file to remove */
    void skip(const uint64_t &id);
    /** \brief skip as interanl one transfer entry
     * \param id id of the file to remove */
    bool skipInternal(const uint64_t &id);
    /// \brief cancel all the transfer
    void cancel();
    //edit the transfer list
    /** \brief remove the selected item
     * \param ids ids is the id list of the selected items */
    void removeItems(const std::vector<uint64_t> &ids);
    /** \brief move on top of the list the selected item
     * \param ids ids is the id list of the selected items */
    void moveItemsOnTop(std::vector<uint64_t> ids);
    /** \brief move up the list the selected item
     * \param ids ids is the id list of the selected items */
    void moveItemsUp(std::vector<uint64_t> ids);
    /** \brief move down the list the selected item
     * \param ids ids is the id list of the selected items */
    void moveItemsDown(std::vector<uint64_t> ids);
    /** \brief move on bottom of the list the selected item
     * \param ids ids is the id list of the selected items */
    void moveItemsOnBottom(std::vector<uint64_t> ids);

    /** \brief give the forced mode, to export/import transfer list */
    void forceMode(const Ultracopier::CopyMode &mode);
    /// \brief export the transfer list into a file
    void exportTransferList(const std::string &fileName);
    /// \brief import the transfer list into a file
    void importTransferList(const std::string &fileName);

    /// \brief set the folder local collision
    void setFolderCollision(const FolderExistsAction &alwaysDoThisActionForFolderExists);
    /** \brief to set the speed limitation
     * -1 if not able, 0 if disabled */
    bool setSpeedLimitation(const int64_t &speedLimitation);
    /// \brief set the copy info and options before runing
    void setRightTransfer(const bool doRightTransfer);
    /// \brief set keep date
    void setKeepDate(const bool keepDate);
    /// \brief set block size in KB
    void setBlockSize(const int blockSize);
    /// \brief set auto start
    void setAutoStart(const bool autoStart);
    #ifdef ULTRACOPIER_PLUGIN_RSYNC
    /// \brief set rsync
    void setRsync(const bool rsync);
    #endif
    /// \brief set check destination folder
    void setCheckDestinationFolderExists(const bool checkDestinationFolderExists);
    /// \brief set data local to the thread
    void setAlwaysFileExistsAction(const FileExistsAction &alwaysDoThisActionForFileExists);
    /// \brief do new actions, start transfer
    void doNewActions_start_transfer();
    /** \brief lunch the pre-op or inode op
      1) locate the next next item to do into the both list
        1a) optimisation posible on the mkpath/rmpath
      2) determine what need be lunched
      3) lunch it, rerun the 2)
      */
    void doNewActions_inode_manipulation();
    /// \brief restart transfer if it can
    void restartTransferIfItCan();
    void getNeedPutAtBottom(const QFileInfo &fileInfo, const std::string &errorString, TransferThread *thread,const ErrorType &errorType);

    /// \brief update the transfer stat
    void newTransferStat(const TransferStat &stat,const quint64 &id);

    void set_osBufferLimit(const unsigned int &osBufferLimit);
    void set_setFilters(const std::vector<Filters_rules> &include,const std::vector<Filters_rules> &exclude);
    void set_sendNewRenamingRules(const std::string &firstRenamingRule,const std::string &otherRenamingRule);
    void set_updateMount();

    //send action done
    void sendActionDone();
    //send progression
    void sendProgression();

    void setTransferAlgorithm(const TransferAlgorithm &transferAlgorithm);
    void setParallelBuffer(int parallelBuffer);
    void setSequentialBuffer(int sequentialBuffer);
    void setParallelizeIfSmallerThan(const unsigned int &parallelizeIfSmallerThan);
    void setMoveTheWholeFolder(const bool &moveTheWholeFolder);
    void setFollowTheStrictOrder(const bool &followTheStrictOrder);
    void setDeletePartiallyTransferredFiles(const bool &deletePartiallyTransferredFiles);
    void setInodeThreads(const int &inodeThreads);
    void setRenameTheOriginalDestination(const bool &renameTheOriginalDestination);
    void setCheckDiskSpace(const bool &checkDiskSpace);
    void setCopyListOrder(const bool &order);
    void exportErrorIntoTransferList(const std::string &fileName);
private:
    QSemaphore          mkpathTransfer;
    std::string             sourceDrive;
    bool                sourceDriveMultiple;
    std::string             destinationDrive;
    std::string             destinationFolder;
    bool                destinationDriveMultiple;
    bool                destinationFolderMultiple;
    DriveManagement     driveManagement;

    bool                stopIt;
    std::vector<ScanFileOrFolder *> scanFileOrFolderThreadsPool;
    int                 numberOfTransferIntoToDoList;
    std::vector<TransferThread *>		transferThreadList;
    ScanFileOrFolder *		newScanThread(Ultracopier::CopyMode mode);
    uint64_t				bytesToTransfer;
    uint64_t				bytesTransfered;
    bool				autoStart;
    #ifdef ULTRACOPIER_PLUGIN_RSYNC
    bool                rsync;
    #endif
    bool				putInPause;
    std::vector<Ultracopier::ReturnActionOnCopyList>	actionDone;///< to action to send to the interface
    uint64_t				idIncrementNumber;///< to store the last id returned
    int64_t				actualRealByteTransfered;
    int                 maxSpeed;///< in KB/s, assume as 0KB/s as default like every where
    FolderExistsAction	alwaysDoThisActionForFolderExists;
    bool				checkDestinationFolderExists;
    bool				doChecksum;
    bool				checksumIgnoreIfImpossible;
    bool				checksumOnlyOnError;
    bool				osBuffer;
    bool				osBufferLimited;
    unsigned int        parallelizeIfSmallerThan;
    bool                moveTheWholeFolder;
    bool                followTheStrictOrder;
    bool                deletePartiallyTransferredFiles;
    int                 sequentialBuffer;
    int                 parallelBuffer;
    int                 inodeThreads;
    bool                renameTheOriginalDestination;
    bool                checkDiskSpace;
    bool                copyListOrder;
    std::unordered_map<std::string,uint64_t> requiredSpace;
    std::vector<std::pair<uint64_t,uint32_t> > timeToTransfer;
    unsigned int        putAtBottom;
    unsigned int		osBufferLimit;
    std::vector<Filters_rules>		include,exclude;
    Ultracopier::CopyMode		mode;
    bool				forcedMode;
    std::string				firstRenamingRule;
    std::string				otherRenamingRule;
    #ifdef ULTRACOPIER_PLUGIN_SPEED_SUPPORT
    int                 multiForBigSpeed;
    #endif
    /* here to prevent:
    QObject::killTimer: timers cannot be stopped from another thread
    QObject::startTimer: timers cannot be started from another thread */
    #ifdef ULTRACOPIER_PLUGIN_SPEED_SUPPORT
    QTimer *clockForTheCopySpeed;	///< For the speed throttling
    #endif

    inline static Ultracopier::ItemOfCopyList actionToDoTransferToItemOfCopyList(const ActionToDoTransfer &actionToDoTransfer);
    //add file transfer to do
    uint64_t addToTransfer(const QFileInfo& source,const QFileInfo& destination,const Ultracopier::CopyMode& mode);
    //generate id number
    uint64_t generateIdNumber();
    //warning the first entry is accessible will copy
    bool removeSingleItem(const uint64_t &id);
    //put on top
    bool moveOnTopItem(const uint64_t &id);
    //move up
    bool moveUpItem(const uint64_t &id);
    //move down
    bool moveDownItem(const uint64_t &id);
    //put on bottom
    bool moveOnBottomItem(const uint64_t &id);
    //general transfer
    void startGeneralTransfer();
    //debug windows if needed
    #ifdef ULTRACOPIER_PLUGIN_DEBUG_WINDOW
    QTimer timerUpdateDebugDialog;
    #endif
    void detectDrivesOfCurrentTransfer(const std::vector<std::string> &sources,const std::string &destination);
    FacilityInterface * facilityInterface;
    QSemaphore waitConstructor,waitCancel;
    int actionToDoListTransfer_count,actionToDoListInode_count;
    bool doTransfer,doInode;
    int64_t oversize;//used as temp variable
    int64_t currentProgression;
    int64_t copiedSize,totalSize,localOverSize;
    std::vector<Ultracopier::ProgressionItem> progressionList;
    //memory variable for transfer thread creation
    bool doRightTransfer;
    bool keepDate;
    int blockSize;//in Bytes
    #ifdef ULTRACOPIER_PLUGIN_SPEED_SUPPORT
    int blockSizeAfterSpeedLimitation;//in Bytes
    #endif
    std::vector<std::string> drives;
    FileExistsAction alwaysDoThisActionForFileExists;
    //to return value to the copyEngine
    bool returnBoolToCopyEngine;
    std::pair<quint64,quint64> returnPairQuint64ToCopyEngine;
    std::vector<Ultracopier::ItemOfCopyList> returnListItemOfCopyListToCopyEngine;
    Ultracopier::ItemOfCopyList returnItemOfCopyListToCopyEngine;
    Ultracopier::ProgressionItem tempItem;

    void realByteTransfered();
    int getNumberOfTranferRuning() const;
    bool needMoreSpace() const;
private slots:
    void scanThreadHaveFinishSlot();
    void scanThreadHaveFinish(bool skipFirstRemove=false);
    void autoStartAndCheckSpace();
    void updateTheStatus();
    void fileTransfer(const QFileInfo &sourceFileInfo,const QFileInfo &destinationFileInfo,const Ultracopier::CopyMode &mode);
    //mkpath event
    void mkPathFirstFolderFinish();
    /** \brief put the current file at bottom in case of error
    \note ONLY IN CASE OF ERROR */
    void transferPutAtBottom();
    //transfer is finished
    void transferInodeIsClosed();
    //debug windows if needed
    #ifdef ULTRACOPIER_PLUGIN_DEBUG_WINDOW
    void timedUpdateDebugDialog();
    #endif
    //dialog message
    /// \note Can be call without queue because all call will be serialized
    void fileAlreadyExists(const QFileInfo &source,const QFileInfo &destination,const bool &isSame);
    /// \note Can be call without queue because all call will be serialized
    void errorOnFile(const QFileInfo &fileInfo,const std::string &errorString, const ErrorType &errorType);
    /// \note Can be call without queue because all call will be serialized
    void folderAlreadyExists(const QFileInfo &source,const QFileInfo &destination,const bool &isSame);
    /// \note Can be call without queue because all call will be serialized
    void errorOnFolder(const QFileInfo &fileInfo, const std::string &errorString, const ErrorType &errorType);
    //to run the thread
    void run();
    /// \to create transfer thread
    void createTransferThread();
    void deleteTransferThread();
    //mk path to do
    uint64_t addToMkPath(const QFileInfo& source, const QFileInfo& destination, const int &inode);
    //add rm path to do
    void addToMovePath(const QFileInfo& source,const QFileInfo& destination, const int& inodeToRemove);
    //add to real move
    void addToRealMove(const QFileInfo& source,const QFileInfo& destination);
    #ifdef ULTRACOPIER_PLUGIN_RSYNC
    //rsync rm
    void addToRmForRsync(const QFileInfo& destination);
    #endif
    //send the progression, after full reset of the interface (then all is empty)
    void syncTransferList_internal();

    void checkIfReadyToCancel();
signals:
    //send information about the copy
    void actionInProgess(const Ultracopier::EngineActionInProgress &) const;	//should update interface information on this event

    void newActionOnList(const std::vector<Ultracopier::ReturnActionOnCopyList> &) const;///very important, need be temporized to group the modification to do and not flood the interface
    void syncReady() const;
    void doneTime(const std::vector<std::pair<uint64_t,uint32_t> >&) const;

    /** \brief to get the progression for a specific file
     * \param id the id of the transfer, id send during population the transfer list
     * first = current transfered byte, second = byte to transfer */
    void pushFileProgression(const std::vector<Ultracopier::ProgressionItem> &progressionList) const;
    //get information about the copy
    /** \brief to get the general progression
     * first = current transfered byte, second = byte to transfer */
    void pushGeneralProgression(const uint64_t &,const uint64_t &) const;

    void newFolderListing(const std::string &path) const;
    void isInPause(const bool &) const;

    //when can be deleted
    void canBeDeleted() const;
    void haveNeedPutAtBottom(bool needPutAtBottom,const QFileInfo &fileInfo,const std::string &errorString,TransferThread * thread,const ErrorType &errorType) const;

    //send error occurred
    void error(const std::string &path,const uint64_t &size,const uint64_t &mtime,const std::string &error) const;
    void errorToRetry(const std::string &source,const std::string &destination,const std::string &error) const;
    //for the extra logging
    void rmPath(const std::string &path) const;
    void mkPath(const std::string &path) const;
    /// \brief To debug source
    #ifdef ULTRACOPIER_PLUGIN_DEBUG
    void debugInformation(const Ultracopier::DebugLevel &level,const std::string &fonction,const std::string &text,const std::string &file,const int &ligne) const;
    #endif
    #ifdef ULTRACOPIER_PLUGIN_DEBUG_WINDOW
    void updateTheDebugInfo(const std::vector<std::string> &,const std::vector<std::string>&,const int &) const;
    #endif

    //other signal
    /// \note Can be call without queue because all call will be serialized
    void send_fileAlreadyExists(const QFileInfo &source,const QFileInfo &destination,const bool &isSame,TransferThread * thread) const;
    /// \note Can be call without queue because all call will be serialized
    void send_errorOnFile(const QFileInfo &fileInfo,const std::string &errorString,TransferThread * thread, const ErrorType &errorType) const;
    /// \note Can be call without queue because all call will be serialized
    void send_folderAlreadyExists(const QFileInfo &source,const QFileInfo &destination,const bool &isSame,ScanFileOrFolder * thread) const;
    /// \note Can be call without queue because all call will be serialized
    void send_errorOnFolder(const QFileInfo &fileInfo,const std::string &errorString,ScanFileOrFolder * thread, const ErrorType &errorType) const;
    //send the progression
    void send_syncTransferList() const;
    //mkpath error event
    void mkPathErrorOnFolder(const QFileInfo &fileInfo,const std::string &errorString,const ErrorType &errorType) const;
    //to close
    void tryCancel() const;
    //to ask new transfer thread
    void askNewTransferThread() const;

    void warningTransferList(const std::string &warning) const;
    void errorTransferList(const std::string &error) const;
    void send_sendNewRenamingRules(const std::string &firstRenamingRule,const std::string &otherRenamingRule) const;
    void send_realBytesTransfered(const uint64_t &) const;

    void send_setTransferAlgorithm(TransferAlgorithm transferAlgorithm) const;
    void send_parallelBuffer(const int &parallelBuffer) const;
    void send_sequentialBuffer(const int &sequentialBuffer) const;
    void send_parallelizeIfSmallerThan(const int &parallelizeIfSmallerThan) const;
    void send_updateMount();
    void missingDiskSpace(std::vector<Diskspace> list) const;
};

#endif // LISTTHREAD_H