Welcome to mirror list, hosted at ThFree Co, Russian Federation.

csyncthread.cpp « mirall « src - github.com/owncloud/client.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 4e2f613920f129f183e4d496f98568202d432d18 (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
/*
 * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
 * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 */

#include <QDebug>
#include <QDir>
#include <QMutexLocker>
#include <QThread>
#include <QStringList>
#include <QTextStream>
#include <QTime>
#include <QDebug>

#include "mirall/csyncthread.h"
#include "mirall/mirallconfigfile.h"

namespace Mirall {

/* static variables to hold the credentials */
QString CSyncThread::_user;
QString CSyncThread::_passwd;
QString CSyncThread::_csyncConfigDir;  // to be able to remove the lock file.

QMutex CSyncThread::_mutex;

 int CSyncThread::checkPermissions( TREE_WALK_FILE* file, void *data )
 {
     WalkStats *wStats = static_cast<WalkStats*>(data);

     if( !wStats ) {
         qDebug() << "WalkStats is zero - must not be!";
         return -1;
     }

     wStats->seenFiles++;

     switch(file->instruction) {
     case CSYNC_INSTRUCTION_NONE:

         break;
     case CSYNC_INSTRUCTION_EVAL:
         wStats->eval++;
         break;
     case CSYNC_INSTRUCTION_REMOVE:
         wStats->removed++;
         break;
     case CSYNC_INSTRUCTION_RENAME:
         wStats->renamed++;
         break;
     case CSYNC_INSTRUCTION_NEW:
         wStats->newFiles++;
         break;
     case CSYNC_INSTRUCTION_CONFLICT:
         wStats->conflicts++;
         break;
     case CSYNC_INSTRUCTION_IGNORE:
         wStats->ignores++;
         break;
     case CSYNC_INSTRUCTION_SYNC:
         wStats->sync++;
         break;
     case CSYNC_INSTRUCTION_STAT_ERROR:
     case CSYNC_INSTRUCTION_ERROR:
         /* instructions for the propagator */
     case CSYNC_INSTRUCTION_DELETED:
     case CSYNC_INSTRUCTION_UPDATED:
         wStats->error++;
         wStats->errorType = WALK_ERROR_INSTRUCTIONS;
         break;
     default:
         wStats->error++;
         wStats->errorType = WALK_ERROR_WALK;
         break;
     }

     if( file ) {
         QString source(wStats->sourcePath);
         source.append(file->path);
         QFileInfo fi(source);

         if( fi.isDir()) {  // File type directory.
            if( !(fi.isWritable() && fi.isExecutable()) ) {
                 wStats->errorType = WALK_ERROR_DIR_PERMS;
             }
         }
     }

     // qDebug() << wStats->seenFiles << ". Path: " << file->path << ": uid= " << file->uid << " - type: " << file->type;
     if( wStats->errorType != WALK_ERROR_NONE ) {
         return -1;
     }
     return 0;
 }

CSyncThread::CSyncThread(const QString &source, const QString &target, bool localCheckOnly)

    : _source(source)
    , _target(target)
    , _localCheckOnly( localCheckOnly )

{
    _mutex.lock();
    if( ! _source.endsWith('/')) _source.append('/');
    _mutex.unlock();
}

CSyncThread::~CSyncThread()
{

}

void CSyncThread::run()
{
    CSYNC *csync;

    WalkStats *wStats = new WalkStats;
    QTime walkTime;

    wStats->sourcePath = 0;
    wStats->errorType  = 0;
    wStats->eval       = 0;
    wStats->removed    = 0;
    wStats->renamed    = 0;
    wStats->newFiles   = 0;
    wStats->ignores    = 0;
    wStats->sync       = 0;
    wStats->seenFiles  = 0;
    wStats->conflicts  = 0;
    wStats->error      = 0;

    _mutex.lock();
    if( csync_create(&csync,
                          _source.toLocal8Bit().data(),
                          _target.toLocal8Bit().data()) < 0 ) {
        emit csyncError( tr("CSync create failed.") );
    }
    // FIXME: Check if we really need this stringcopy!
    wStats->sourcePath = qstrdup( _source.toLocal8Bit().constData() );
    _csyncConfigDir = QString::fromLocal8Bit( csync_get_config_dir( csync ));
    _mutex.unlock();

    qDebug() << "## CSync Thread local only: " << _localCheckOnly;
    csync_set_auth_callback( csync, getauth );
    csync_enable_conflictcopys(csync);


    MirallConfigFile cfg;
    QString excludeList = cfg.excludeFile();

    if( !excludeList.isEmpty() ) {
        qDebug() << "==== added CSync exclude List: " << excludeList.toAscii();
        csync_add_exclude_list( csync, excludeList.toAscii() );
    }

    QTime t;
    t.start();

    _mutex.lock();
    if( _localCheckOnly ) {
        csync_set_local_only( csync, true );
    }
    _mutex.unlock();

    if( csync_init(csync) < 0 ) {
        CSYNC_ERROR_CODE err = csync_get_error( csync );
        QString errStr;

        switch( err ) {
        case CSYNC_ERR_LOCK:
            errStr = tr("CSync failed to create a lock file.");
            break;
        case CSYNC_ERR_STATEDB_LOAD:
            errStr = tr("CSync failed to load the state db.");
            break;
        case CSYNC_ERR_TIMESKEW:
            errStr = tr("The system time between the local machine and the server differs "
                        "too much. Please use a time syncronization service (ntp) on both machines.");
            break;
        case CSYNC_ERR_FILESYSTEM:
            errStr = tr("CSync could not detect the filesystem type.");
            break;
        case CSYNC_ERR_TREE:
            errStr = tr("CSync got an error while processing internal trees.");
            break;
        case CSYNC_ERR_ACCESS_FAILED:
            errStr = tr("<p>The target directory %1 does not exist.</p><p>Please create it and try again.</p>").arg(_target);
            break;
        case CSYNC_ERR_MODULE:
            errStr = tr("<p>The ownCloud plugin for csync could not be loaded.<br/>Please verify the installation!</p>");
            break;
        case CSYNC_ERR_LOCAL_CREATE:
        case CSYNC_ERR_LOCAL_STAT:
            errStr = tr("The local filesystem can not be written. Please check permissions.");
            break;
        case CSYNC_ERR_REMOTE_CREATE:
        case CSYNC_ERR_REMOTE_STAT:
            errStr = tr("A remote file can not be written. Please check the remote access.");
            break;
        default:
            errStr = tr("An internal error number %1 happend.").arg( (int) err );
        }
        qDebug() << " #### ERROR String emitted: " << errStr;
        emit csyncError(errStr);
        goto cleanup;
    }

    qDebug() << "############################################################### >>";
    if( csync_update(csync) < 0 ) {
        emit csyncError(tr("CSync Update failed."));
        goto cleanup;
    }
    qDebug() << "<<###############################################################";

    csync_set_userdata(csync, wStats);

    walkTime.start();
    if( csync_walk_local_tree(csync, &checkPermissions, 0) < 0 ) {
        qDebug() << "Error in treewalk.";
        if( wStats->errorType == WALK_ERROR_DIR_PERMS ) {
            emit csyncError(tr("The local filesystem has directories which are write protected.\n"
                               "That prevents ownCloud from successful syncing.\n"
                               "Please make sure that all directories are writeable."));
        } else if( wStats->errorType == WALK_ERROR_WALK ) {
            emit csyncError(tr("CSync encountered an error while examining the file system.\n"
                               "Syncing is not possible."));
        } else if( wStats->errorType == WALK_ERROR_INSTRUCTIONS ) {
            emit csyncError(tr("CSync update generated a strange instruction.\n"
                               "Please write a bug report."));
        }
        emit csyncError(tr("Local filesystem problems. Better disable Syncing and check."));
        goto cleanup;
    }
    qDebug() << " ..... Local walk finished: " << walkTime.elapsed();

    // emit the treewalk results. Do not touch the wStats after this.
    emit treeWalkResult(wStats);

    _mutex.lock();
    if( _localCheckOnly ) {
        _mutex.unlock();
        // we have to go out here as its local check only.
        goto cleanup;
    } else {
        _mutex.unlock();
        // check if we can write all over.

        if( csync_reconcile(csync) < 0 ) {
            emit csyncError(tr("CSync reconcile failed."));
            goto cleanup;
        }
        if( csync_propagate(csync) < 0 ) {
            emit csyncError(tr("CSync propagate failed."));
            goto cleanup;
        }
    }
cleanup:
    csync_destroy(csync);
    /*
     * Attention: do not delete the wStat memory here. it is deleted in the
     * slot catching the signel treeWalkResult because this thread can faster
     * die than the slot has read out the data.
     */
    qDebug() << "CSync run took " << t.elapsed() << " Milliseconds";
}


void CSyncThread::setUserPwd( const QString& user, const QString& passwd )
{
    _mutex.lock();
    _user = user;
    _passwd = passwd;
    _mutex.unlock();
}

QString CSyncThread::csyncConfigDir()
{
    return _csyncConfigDir;
}

int CSyncThread::getauth(const char *prompt,
                         char *buf,
                         size_t len,
                         int echo,
                         int verify,
                         void *userdata
                         )
{
    QString qPrompt = QString::fromLocal8Bit( prompt ).trimmed();
    _mutex.lock();

    if( qPrompt == QString::fromLocal8Bit("Enter your username:") ) {
        // qDebug() << "OOO Username requested!";
        strncpy( buf, _user.toLocal8Bit().constData(), len );
    } else if( qPrompt == QString::fromLocal8Bit("Enter your password:") ) {
        // qDebug() << "OOO Password requested!";
        strncpy( buf, _passwd.toLocal8Bit().constData(), len );
    } else {
        if( qPrompt.startsWith( QLatin1String("There are problems with the SSL certificate:"))) {
            // SSL is requested. If the program came here, the SSL check was done by mirall
            // the answer is simply yes here.
            strncpy( buf, "yes", 3 );
        } else {
            qDebug() << "Unknown prompt: <" << prompt << ">";
        }
    }
    _mutex.unlock();
}

}