csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) { struct _tdirent *dirent = NULL; dhandle_t *handle = NULL; csync_vio_file_stat_t *file_stat = NULL; handle = (dhandle_t *) dhandle; errno = 0; dirent = _treaddir(handle->dh); if (dirent == NULL) { if (errno) { goto err; } else { return NULL; } } file_stat = csync_vio_file_stat_new(); if (file_stat == NULL) { goto err; } file_stat->name = c_utf8_from_locale(dirent->d_name); file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; /* Check for availability of d_type, see manpage. */ #ifdef _DIRENT_HAVE_D_TYPE switch (dirent->d_type) { case DT_FIFO: case DT_SOCK: case DT_CHR: case DT_BLK: break; case DT_DIR: case DT_REG: file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; if (dirent->d_type == DT_DIR) { file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; } else { file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR; } break; case DT_UNKNOWN: file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; default: break; } #endif return file_stat; err: SAFE_FREE(file_stat); return NULL; }
csync_vio_file_stat_t *csync_vio_convert_file_stat(csync_file_stat_t *st) { csync_vio_file_stat_t *vfs = NULL; if (st == NULL) { return NULL; } vfs = csync_vio_file_stat_new(); if (vfs == NULL) { return NULL; } vfs->acl = NULL; if (st->pathlen > 0) { vfs->name = c_strdup(st->path); } vfs->uid = st->uid; vfs->gid = st->gid; vfs->atime = 0; vfs->mtime = st->modtime; vfs->ctime = 0; vfs->size = st->size; vfs->blksize = 0; /* Depricated. */ vfs->blkcount = 0; vfs->mode = st->mode; vfs->device = 0; vfs->inode = st->inode; vfs->nlink = st->nlink; /* fields. */ vfs->fields = CSYNC_VIO_FILE_STAT_FIELDS_TYPE + CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS + CSYNC_VIO_FILE_STAT_FIELDS_INODE + CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT + CSYNC_VIO_FILE_STAT_FIELDS_SIZE + CSYNC_VIO_FILE_STAT_FIELDS_MTIME + CSYNC_VIO_FILE_STAT_FIELDS_UID + CSYNC_VIO_FILE_STAT_FIELDS_GID; if (st->type == CSYNC_FTW_TYPE_DIR) vfs->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; else if (st->type == CSYNC_FTW_TYPE_FILE) vfs->type = CSYNC_VIO_FILE_TYPE_REGULAR; else if (st->type == CSYNC_FTW_TYPE_SLINK) vfs->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; else vfs->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; return vfs; }
static qint64 getSizeWithCsync(const QString& filename) { qint64 result = 0; csync_vio_file_stat_t* stat = csync_vio_file_stat_new(); if (csync_vio_local_stat(filename.toUtf8().data(), stat) != -1 && (stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_SIZE)) { result = stat->size; } else { qDebug() << "Could not get size time for" << filename << "with csync"; } csync_vio_file_stat_destroy(stat); return result; }
time_t FileSystem::getModTime(const QString &filename) { csync_vio_file_stat_t* stat = csync_vio_file_stat_new(); qint64 result = -1; if (csync_vio_local_stat(filename.toUtf8().data(), stat) != -1 && (stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_MTIME)) { result = stat->mtime; } else { qDebug() << "Could not get modification time for" << filename << "with csync, using QFileInfo"; result = Utility::qDateTimeToTime_t(QFileInfo(filename).lastModified()); } csync_vio_file_stat_destroy(stat); return result; }
static void check_csync_vio_stat_file(void **state) { CSYNC *csync = *state; csync_vio_file_stat_t *fs; int rc; fs = csync_vio_file_stat_new(); assert_non_null(fs); rc = csync_vio_stat(csync, CSYNC_TEST_FILE, fs); assert_int_equal(rc, 0); assert_string_equal(fs->name, "file.txt"); assert_int_equal(fs->type, CSYNC_VIO_FILE_TYPE_REGULAR); csync_vio_file_stat_destroy(fs); }
static void check_csync_vio_stat_dir(void **state) { CSYNC *csync = *state; csync_vio_file_stat_t *fs; int rc; fs = csync_vio_file_stat_new(); assert_non_null(fs); rc = csync_vio_stat(csync, CSYNC_TEST_DIR, fs); assert_int_equal(rc, 0); assert_string_equal(fs->name, "csync_test"); assert_int_equal(fs->type, CSYNC_VIO_FILE_TYPE_DIRECTORY); csync_vio_file_stat_destroy(fs); }
csync_vio_file_stat_t* csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat) { csync_vio_file_stat_t *file_stat_cpy = csync_vio_file_stat_new(); memcpy(file_stat_cpy, file_stat, sizeof(csync_vio_file_stat_t)); if (file_stat_cpy->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) { file_stat_cpy->etag = c_strdup(file_stat_cpy->etag); } if (file_stat_cpy->directDownloadCookies) { file_stat_cpy->directDownloadCookies = c_strdup(file_stat_cpy->directDownloadCookies); } if (file_stat_cpy->directDownloadUrl) { file_stat_cpy->directDownloadUrl = c_strdup(file_stat_cpy->directDownloadUrl); } if (file_stat_cpy->checksumHeader) { file_stat_cpy->checksumHeader = c_strdup(file_stat_cpy->checksumHeader); } file_stat_cpy->name = c_strdup(file_stat_cpy->name); return file_stat_cpy; }
csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) { dhandle_t *handle = NULL; csync_vio_file_stat_t *file_stat = NULL; handle = (dhandle_t *) dhandle; errno = 0; file_stat = csync_vio_file_stat_new(); if (file_stat == NULL) { goto err; } file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; // the win32 functions get the first valid entry with the opendir // thus we must not jump to next entry if it was the first find. if( handle->firstFind ) { handle->firstFind = 0; } else { if( FindNextFile(handle->hFind, &(handle->ffd)) == 0 ) { // might be error, check! int dwError = GetLastError(); if (dwError != ERROR_NO_MORE_FILES) { errno = EACCES; // no more files is fine. Otherwise EACCESS } goto err; } } file_stat->name = c_utf8_from_locale(handle->ffd.cFileName); file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; } else { file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR; } return file_stat; err: SAFE_FREE(file_stat); return NULL; }
/* File tree walker */ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, unsigned int depth) { char *filename = NULL; char *d_name = NULL; csync_vio_handle_t *dh = NULL; csync_vio_file_stat_t *dirent = NULL; csync_vio_file_stat_t *fs = NULL; csync_file_stat_t *previous_fs = NULL; int read_from_db = 0; int rc = 0; int res = 0; bool do_read_from_db = (ctx->current == REMOTE_REPLICA && ctx->remote.read_from_db); if (uri[0] == '\0') { errno = ENOENT; ctx->status_code = CSYNC_STATUS_PARAM_ERROR; goto error; } read_from_db = ctx->remote.read_from_db; // if the etag of this dir is still the same, its content is restored from the // database. if( do_read_from_db ) { if( ! fill_tree_from_db(ctx, uri) ) { errno = ENOENT; ctx->status_code = CSYNC_STATUS_OPENDIR_ERROR; goto error; } goto done; } if ((dh = csync_vio_opendir(ctx, uri)) == NULL) { int asp = 0; /* permission denied */ ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_OPENDIR_ERROR); if (errno == EACCES) { return 0; } else if(errno == ENOENT) { asp = asprintf( &ctx->error_string, "%s", uri); if (asp < 0) { CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!"); } } else { CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - errno %d", uri, errno); } goto error; } while ((dirent = csync_vio_readdir(ctx, dh))) { const char *path = NULL; size_t ulen = 0; int flen; int flag; d_name = dirent->name; if (d_name == NULL) { ctx->status_code = CSYNC_STATUS_READDIR_ERROR; goto error; } /* skip "." and ".." */ if (d_name[0] == '.' && (d_name[1] == '\0' || (d_name[1] == '.' && d_name[2] == '\0'))) { csync_vio_file_stat_destroy(dirent); dirent = NULL; continue; } flen = asprintf(&filename, "%s/%s", uri, d_name); if (flen < 0) { csync_vio_file_stat_destroy(dirent); dirent = NULL; ctx->status_code = CSYNC_STATUS_MEMORY_ERROR; goto error; } /* Create relative path */ switch (ctx->current) { case LOCAL_REPLICA: ulen = strlen(ctx->local.uri) + 1; break; case REMOTE_REPLICA: ulen = strlen(ctx->remote.uri) + 1; break; default: break; } if (((size_t)flen) < ulen) { csync_vio_file_stat_destroy(dirent); dirent = NULL; ctx->status_code = CSYNC_STATUS_UNSUCCESSFUL; goto error; } path = filename + ulen; /* skip ".csync_journal.db" and ".csync_journal.db.ctmp" */ if (c_streq(path, ".csync_journal.db") || c_streq(path, ".csync_journal.db.ctmp") || c_streq(path, ".csync_journal.db.ctmp-journal") || c_streq(path, ".csync-progressdatabase")) { csync_vio_file_stat_destroy(dirent); dirent = NULL; SAFE_FREE(filename); continue; } /* Only for the local replica we have to stat(), for the remote one we have all data already */ if (ctx->replica == LOCAL_REPLICA) { fs = csync_vio_file_stat_new(); res = csync_vio_stat(ctx, filename, fs); } else { fs = dirent; res = 0; } if( res == 0) { switch (fs->type) { case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK: flag = CSYNC_FTW_FLAG_SLINK; break; case CSYNC_VIO_FILE_TYPE_DIRECTORY: flag = CSYNC_FTW_FLAG_DIR; break; case CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE: case CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE: case CSYNC_VIO_FILE_TYPE_SOCKET: flag = CSYNC_FTW_FLAG_SPEC; break; case CSYNC_VIO_FILE_TYPE_FIFO: flag = CSYNC_FTW_FLAG_SPEC; break; default: flag = CSYNC_FTW_FLAG_FILE; break; }; } else { flag = CSYNC_FTW_FLAG_NSTAT; } if( ctx->current == LOCAL_REPLICA ) { char *etag = NULL; int len = strlen( path ); uint64_t h = c_jhash64((uint8_t *) path, len, 0); etag = csync_statedb_get_etag( ctx, h ); if( etag ) { SAFE_FREE(fs->etag); fs->etag = etag; fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ETAG; if( c_streq(etag, "")) { CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Uniq ID from Database is EMPTY: %s", path); } else { CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Uniq ID from Database: %s -> %s", path, fs->etag ? fs->etag : "<NULL>" ); } } } previous_fs = ctx->current_fs; /* Call walker function for each file */ rc = fn(ctx, filename, fs, flag); /* this function may update ctx->current and ctx->read_from_db */ if (ctx->current_fs && previous_fs && ctx->current_fs->child_modified) { previous_fs->child_modified = ctx->current_fs->child_modified; } /* Only for the local replica we have to destroy stat(), for the remote one it is a pointer to dirent */ if (ctx->replica == LOCAL_REPLICA) { csync_vio_file_stat_destroy(fs); } if (rc < 0) { if (CSYNC_STATUS_IS_OK(ctx->status_code)) { ctx->status_code = CSYNC_STATUS_UPDATE_ERROR; } ctx->current_fs = previous_fs; goto error; } if (flag == CSYNC_FTW_FLAG_DIR && depth && (!ctx->current_fs || ctx->current_fs->instruction != CSYNC_INSTRUCTION_IGNORE)) { rc = csync_ftw(ctx, filename, fn, depth - 1); if (rc < 0) { ctx->current_fs = previous_fs; goto error; } if (ctx->current_fs && !ctx->current_fs->child_modified && ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL) { ctx->current_fs->instruction = CSYNC_INSTRUCTION_NONE; ctx->current_fs->should_update_etag = true; } } if (flag == CSYNC_FTW_FLAG_DIR && ctx->current_fs && (ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL || ctx->current_fs->instruction == CSYNC_INSTRUCTION_NEW || ctx->current_fs->instruction == CSYNC_INSTRUCTION_EVAL_RENAME)) { ctx->current_fs->should_update_etag = true; } ctx->current_fs = previous_fs; ctx->remote.read_from_db = read_from_db; SAFE_FREE(filename); csync_vio_file_stat_destroy(dirent); dirent = NULL; } csync_vio_closedir(ctx, dh); CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, " <= Closing walk for %s with read_from_db %d", uri, read_from_db); done: csync_vio_file_stat_destroy(dirent); SAFE_FREE(filename); return rc; error: ctx->remote.read_from_db = read_from_db; if (dh != NULL) { csync_vio_closedir(ctx, dh); } SAFE_FREE(filename); return -1; }
/* create a file stat, caller must free memory */ static csync_vio_file_stat_t* create_fstat(const char *name, ino_t inode, nlink_t nlink, time_t mtime) { csync_vio_file_stat_t *fs = NULL; time_t t; fs = csync_vio_file_stat_new(); if (fs == NULL) { return NULL; } if (name && *name) { fs->name = c_strdup(name); } else { fs->name = c_strdup("file.txt"); } if (fs->name == NULL) { csync_vio_file_stat_destroy(fs); return NULL; } fs->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; fs->type = CSYNC_VIO_FILE_TYPE_REGULAR; fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; fs->mode = 0644; fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_PERMISSIONS; if (inode == 0) { fs->inode = 619070; } else { fs->inode = inode; } fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_INODE; fs->device = 0; fs->size = 157459; fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; if (nlink == 0) { fs->nlink = 1; } else { fs->nlink = nlink; } fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_LINK_COUNT; fs->uid = 1000; fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_UID; fs->gid = 1000; fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_GID; fs->blkcount = 312; fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_COUNT; fs->blksize = 4096; fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_BLOCK_SIZE; if (mtime == 0) { fs->atime = fs->ctime = fs->mtime = time(&t); } else { fs->atime = fs->ctime = fs->mtime = mtime; } fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME; fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME; fs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; return fs; }
csync_vio_file_stat_t *csync_vio_local_readdir(csync_vio_handle_t *dhandle) { dhandle_t *handle = NULL; csync_vio_file_stat_t *file_stat = NULL; ULARGE_INTEGER FileIndex; DWORD rem; handle = (dhandle_t *) dhandle; errno = 0; file_stat = csync_vio_file_stat_new(); if (file_stat == NULL) { errno = ENOMEM; goto err; } file_stat->fields = CSYNC_VIO_FILE_STAT_FIELDS_NONE; // the win32 functions get the first valid entry with the opendir // thus we must not jump to next entry if it was the first find. if( handle->firstFind ) { handle->firstFind = 0; } else { if( FindNextFile(handle->hFind, &(handle->ffd)) == 0 ) { // might be error, check! int dwError = GetLastError(); if (dwError != ERROR_NO_MORE_FILES) { errno = EACCES; // no more files is fine. Otherwise EACCESS } goto err; } } file_stat->name = c_utf8_from_locale(handle->ffd.cFileName); file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && handle->ffd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) { file_stat->flags = CSYNC_VIO_FILE_FLAGS_SYMLINK; file_stat->type = CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK; } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE || handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) { file_stat->type = CSYNC_VIO_FILE_TYPE_UNKNOWN; } else if (handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { file_stat->type = CSYNC_VIO_FILE_TYPE_DIRECTORY; } else { file_stat->type = CSYNC_VIO_FILE_TYPE_REGULAR; } file_stat->flags = CSYNC_VIO_FILE_FLAGS_NONE; /* Check for the hidden flag */ if( handle->ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) { file_stat->flags |= CSYNC_VIO_FILE_FLAGS_HIDDEN; } file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_FLAGS; file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_TYPE; file_stat->size = (handle->ffd.nFileSizeHigh * ((int64_t)(MAXDWORD)+1)) + handle->ffd.nFileSizeLow; file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_SIZE; file_stat->atime = FileTimeToUnixTime(&handle->ffd.ftLastAccessTime, &rem); file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_ATIME; file_stat->mtime = FileTimeToUnixTime(&handle->ffd.ftLastWriteTime, &rem); /* CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Local File MTime: %llu", (unsigned long long) buf->mtime ); */ file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_MTIME; file_stat->ctime = FileTimeToUnixTime(&handle->ffd.ftCreationTime, &rem); file_stat->fields |= CSYNC_VIO_FILE_STAT_FIELDS_CTIME; return file_stat; err: SAFE_FREE(file_stat); return NULL; }
/* File tree walker */ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn, unsigned int depth) { char errbuf[256] = {0}; char *filename = NULL; char *d_name = NULL; csync_vio_handle_t *dh = NULL; csync_vio_file_stat_t *dirent = NULL; csync_vio_file_stat_t *fs = NULL; int rc = 0; if (uri[0] == '\0') { errno = ENOENT; goto error; } if ((dh = csync_vio_opendir(ctx, uri)) == NULL) { /* permission denied */ if (errno == EACCES) { return 0; } else { CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "opendir failed for %s - %s", uri, strerror_r(errno, errbuf, sizeof(errbuf))); goto error; } } while ((dirent = csync_vio_readdir(ctx, dh))) { const char *path = NULL; int flag; d_name = dirent->name; if (d_name == NULL) { goto error; } /* skip "." and ".." */ if (d_name[0] == '.' && (d_name[1] == '\0' || (d_name[1] == '.' && d_name[2] == '\0'))) { csync_vio_file_stat_destroy(dirent); dirent = NULL; continue; } if (asprintf(&filename, "%s/%s", uri, d_name) < 0) { csync_vio_file_stat_destroy(dirent); dirent = NULL; goto error; } /* Create relative path for checking the exclude list */ switch (ctx->current) { case LOCAL_REPLICA: path = filename + strlen(ctx->local.uri) + 1; break; case REMOTE_REPLCIA: path = filename + strlen(ctx->remote.uri) + 1; break; default: break; } /* Check if file is excluded */ if (csync_excluded(ctx, path)) { CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "%s excluded", path); csync_vio_file_stat_destroy(dirent); dirent = NULL; continue; } fs = csync_vio_file_stat_new(); if (csync_vio_stat(ctx, filename, fs) == 0) { switch (fs->type) { case CSYNC_VIO_FILE_TYPE_SYMBOLIC_LINK: flag = CSYNC_FTW_FLAG_SLINK; break; case CSYNC_VIO_FILE_TYPE_DIRECTORY: flag = CSYNC_FTW_FLAG_DIR; break; case CSYNC_VIO_FILE_TYPE_BLOCK_DEVICE: case CSYNC_VIO_FILE_TYPE_CHARACTER_DEVICE: case CSYNC_VIO_FILE_TYPE_SOCKET: flag = CSYNC_FTW_FLAG_SPEC; break; case CSYNC_VIO_FILE_TYPE_FIFO: flag = CSYNC_FTW_FLAG_SPEC; break; default: flag = CSYNC_FTW_FLAG_FILE; break; }; } else { flag = CSYNC_FTW_FLAG_NSTAT; } CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "walk: %s", filename); /* Call walker function for each file */ rc = fn(ctx, filename, fs, flag); csync_vio_file_stat_destroy(fs); if (rc < 0) { csync_vio_closedir(ctx, dh); goto done; } if (flag == CSYNC_FTW_FLAG_DIR && depth) { rc = csync_ftw(ctx, filename, fn, depth - 1); if (rc < 0) { csync_vio_closedir(ctx, dh); goto done; } } SAFE_FREE(filename); csync_vio_file_stat_destroy(dirent); dirent = NULL; } csync_vio_closedir(ctx, dh); done: csync_vio_file_stat_destroy(dirent); SAFE_FREE(filename); return rc; error: SAFE_FREE(filename); return -1; }
/* check time difference between the replicas */ time_t csync_timediff(CSYNC *ctx) { time_t timediff = -1; char errbuf[256] = {0}; char *luri = NULL; char *ruri = NULL; csync_vio_handle_t *fp = NULL; csync_vio_file_stat_t *st = NULL; csync_vio_handle_t *dp = NULL; /* try to open remote dir to get auth */ ctx->replica = ctx->remote.type; dp = csync_vio_opendir(ctx, ctx->remote.uri); if (dp == NULL) { /* * To prevent problems especially with pam_csync we shouldn't try to create the * remote directory here. Just fail! */ strerror_r(errno, errbuf, sizeof(errbuf)); CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Access dienied to remote uri: %s - %s", ctx->remote.uri, errbuf); return -1; } csync_vio_closedir(ctx, dp); if (asprintf(&luri, "%s/.csync_timediff.ctmp", ctx->local.uri) < 0) { goto out; } if (asprintf(&ruri, "%s/.csync_timediff.ctmp", ctx->remote.uri) < 0) { goto out; } /* create temporary file on local */ ctx->replica = ctx->local.type; fp = csync_vio_creat(ctx, luri, 0644); if (fp == NULL) { strerror_r(errno, errbuf, sizeof(errbuf)); CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Unable to create temporary file: %s - %s", luri, errbuf); goto out; } csync_vio_close(ctx, fp); /* Get the modification time */ st = csync_vio_file_stat_new(); if (csync_vio_stat(ctx, luri, st) < 0) { strerror_r(errno, errbuf, sizeof(errbuf)); CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Synchronisation is not possible! %s - %s", luri, errbuf); goto out; } timediff = st->mtime; csync_vio_file_stat_destroy(st); st = NULL; /* create temporary file on remote replica */ ctx->replica = ctx->remote.type; fp = csync_vio_creat(ctx, ruri, 0644); if (fp == NULL) { strerror_r(errno, errbuf, sizeof(errbuf)); CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Unable to create temporary file: %s - %s", ruri, errbuf); goto out; } csync_vio_close(ctx, fp); /* Get the modification time */ st = csync_vio_file_stat_new(); if (csync_vio_stat(ctx, ruri, st) < 0) { strerror_r(errno, errbuf, sizeof(errbuf)); CSYNC_LOG(CSYNC_LOG_PRIORITY_FATAL, "Synchronisation is not possible! %s - %s", ruri, errbuf); goto out; } /* calc time difference */ timediff = llabs(timediff - st->mtime); CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Time difference: %ld seconds", timediff); out: csync_vio_file_stat_destroy(st); ctx->replica = ctx->local.type; csync_vio_unlink(ctx, luri); SAFE_FREE(luri); ctx->replica = ctx->remote.type; csync_vio_unlink(ctx, ruri); SAFE_FREE(ruri); return timediff; }
static int _csync_push_file(CSYNC *ctx, csync_file_stat_t *st) { enum csync_replica_e srep = -1; enum csync_replica_e drep = -1; enum csync_replica_e rep_bak = -1; char *suri = NULL; char *duri = NULL; char *turi = NULL; char *tdir = NULL; csync_vio_handle_t *sfp = NULL; csync_vio_handle_t *dfp = NULL; csync_vio_file_stat_t *tstat = NULL; char errbuf[256] = {0}; char buf[MAX_XFER_BUF_SIZE] = {0}; ssize_t bread = 0; ssize_t bwritten = 0; struct timeval times[2]; int rc = -1; int count = 0; int flags = 0; rep_bak = ctx->replica; switch (ctx->current) { case LOCAL_REPLICA: srep = ctx->local.type; drep = ctx->remote.type; if (asprintf(&suri, "%s/%s", ctx->local.uri, st->path) < 0) { rc = -1; goto out; } if (asprintf(&duri, "%s/%s", ctx->remote.uri, st->path) < 0) { rc = -1; goto out; } break; case REMOTE_REPLCIA: srep = ctx->remote.type; drep = ctx->local.type; if (asprintf(&suri, "%s/%s", ctx->remote.uri, st->path) < 0) { rc = -1; goto out; } if (asprintf(&duri, "%s/%s", ctx->local.uri, st->path) < 0) { rc = -1; goto out; } break; default: break; } /* Open the source file */ ctx->replica = srep; flags = O_RDONLY|O_NOFOLLOW; /* O_NOATIME can only be set by the owner of the file or the superuser */ if (st->uid == ctx->pwd.uid || ctx->pwd.euid == 0) { flags |= O_NOATIME; } sfp = csync_vio_open(ctx, suri, flags, 0); if (sfp == NULL) { if (errno == ENOMEM) { rc = -1; } else { rc = 1; } CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: open(O_RDONLY), error: %s", suri, strerror_r(errno, errbuf, sizeof(errbuf))); goto out; } /* create the temporary file name */ if (asprintf(&turi, "%s.XXXXXX", duri) < 0) { rc = -1; goto out; } /* We just want a random file name here, open checks if the file exists. */ if (c_tmpname(turi) < 0) { rc = -1; goto out; } /* Create the destination file */ ctx->replica = drep; while ((dfp = csync_vio_open(ctx, turi, O_CREAT|O_EXCL|O_WRONLY|O_NOCTTY, C_FILE_MODE)) == NULL) { switch (errno) { case EEXIST: if (count++ > 10) { CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: open(O_CREAT), error: max count exceeded", duri); rc = 1; goto out; } if (c_tmpname(turi) < 0) { rc = -1; goto out; } break; case ENOENT: /* get the directory name */ tdir = c_dirname(turi); if (tdir == NULL) { rc = -1; goto out; } if (csync_vio_mkdirs(ctx, tdir, C_DIR_MODE) < 0) { CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "dir: %s, command: mkdirs, error: %s", tdir, strerror_r(errno, errbuf, sizeof(errbuf))); } break; case ENOMEM: rc = -1; CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: open(O_CREAT), error: %s", turi, strerror_r(errno, errbuf, sizeof(errbuf))); goto out; break; default: CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: open(O_CREAT), error: %s", turi, strerror_r(errno, errbuf, sizeof(errbuf))); rc = 1; goto out; break; } } /* copy file */ for (;;) { ctx->replica = srep; bread = csync_vio_read(ctx, sfp, buf, MAX_XFER_BUF_SIZE); if (bread < 0) { /* read error */ CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: read, error: %s", suri, strerror_r(errno, errbuf, sizeof(errbuf))); rc = 1; goto out; } else if (bread == 0) { /* done */ break; } ctx->replica = drep; bwritten = csync_vio_write(ctx, dfp, buf, bread); if (bwritten < 0 || bread != bwritten) { CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: write, error: bread = %zu, bwritten = %zu - %s", duri, bread, bwritten, strerror_r(errno, errbuf, sizeof(errbuf))); rc = 1; goto out; } } ctx->replica = srep; if (csync_vio_close(ctx, sfp) < 0) { CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: close, error: %s", suri, strerror_r(errno, errbuf, sizeof(errbuf))); } sfp = NULL; ctx->replica = drep; if (csync_vio_close(ctx, dfp) < 0) { dfp = NULL; switch (errno) { /* stop if no space left or quota exceeded */ case ENOSPC: case EDQUOT: CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: close, error: %s", turi, strerror_r(errno, errbuf, sizeof(errbuf))); rc = -1; goto out; break; default: CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: close, error: %s", turi, strerror_r(errno, errbuf, sizeof(errbuf))); break; } } dfp = NULL; /* * Check filesize */ ctx->replica = drep; tstat = csync_vio_file_stat_new(); if (tstat == NULL) { CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: stat, error: %s", turi, strerror_r(errno, errbuf, sizeof(errbuf))); rc = -1; goto out; } if (csync_vio_stat(ctx, turi, tstat) < 0) { switch (errno) { case ENOMEM: rc = -1; break; default: rc = 1; break; } CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: stat, error: %s", turi, strerror_r(errno, errbuf, sizeof(errbuf))); goto out; } if (st->size != tstat->size) { CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, error: incorrect filesize (size: %jd should be %jd)", turi, tstat->size, st->size); rc = 1; goto out; } /* override original file */ ctx->replica = drep; if (csync_vio_rename(ctx, turi, duri) < 0) { switch (errno) { case ENOMEM: rc = -1; break; default: rc = 1; break; } CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: rename, error: %s", duri, strerror_r(errno, errbuf, sizeof(errbuf))); goto out; } /* set mode only if it is not the default mode */ if ((st->mode & 07777) != C_FILE_MODE) { if (csync_vio_chmod(ctx, duri, st->mode) < 0) { switch (errno) { case ENOMEM: rc = -1; break; default: rc = 1; break; } CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "file: %s, command: chmod, error: %s", duri, strerror_r(errno, errbuf, sizeof(errbuf))); goto out; } } /* set owner and group if possible */ if (ctx->pwd.euid == 0) { csync_vio_chown(ctx, duri, st->uid, st->gid); } /* sync time */ times[0].tv_sec = times[1].tv_sec = st->modtime; times[0].tv_usec = times[1].tv_usec = 0; ctx->replica = drep; csync_vio_utimes(ctx, duri, times); /* set instruction for the statedb merger */ st->instruction = CSYNC_INSTRUCTION_UPDATED; CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "PUSHED file: %s", duri); rc = 0; out: ctx->replica = srep; csync_vio_close(ctx, sfp); ctx->replica = drep; csync_vio_close(ctx, dfp); csync_vio_file_stat_destroy(tstat); /* set instruction for the statedb merger */ if (rc != 0) { st->instruction = CSYNC_INSTRUCTION_ERROR; csync_vio_unlink(ctx, turi); } SAFE_FREE(suri); SAFE_FREE(duri); SAFE_FREE(turi); SAFE_FREE(tdir); ctx->replica = rep_bak; return rc; }
static const char* owncloud_get_etag( const char *path ) { ne_request *req = NULL; const char *header = NULL; char *uri = _cleanPath(path); char *cbuf = NULL; csync_vio_file_stat_t *fs = NULL; bool doHeadRequest = false; if (_id_cache.uri && c_streq(path, _id_cache.uri)) { header = _id_cache.id; } doHeadRequest= false; /* ownCloud server doesn't have good support for HEAD yet */ if( !header && doHeadRequest ) { int neon_stat; /* Perform an HEAD request to the resource. HEAD delivers the * ETag header back. */ req = ne_request_create(dav_session.ctx, "HEAD", uri); neon_stat = ne_request_dispatch(req); set_errno_from_neon_errcode( neon_stat ); header = ne_get_response_header(req, "etag"); } /* If the request went wrong or the server did not respond correctly * (that can happen for collections) a stat call is done which translates * into a PROPFIND request. */ if( ! header ) { /* ... and do a stat call. */ fs = csync_vio_file_stat_new(); if(fs == NULL) { DEBUG_WEBDAV( "owncloud_get_etag: memory fault."); errno = ENOMEM; return NULL; } if( owncloud_stat( path, fs ) == 0 ) { header = fs->etag; } } /* In case the result is surrounded by "" cut them away. */ if( header ) { cbuf = csync_normalize_etag(header); } /* fix server problem: If we end up with an empty string, set something strange... */ if( c_streq(cbuf, "") || c_streq(cbuf, "\"\"") ) { SAFE_FREE(cbuf); cbuf = c_strdup("empty_etag"); } DEBUG_WEBDAV("Get file ID for %s: %s", path, cbuf ? cbuf:"<null>"); if( fs ) csync_vio_file_stat_destroy(fs); if( req ) ne_request_destroy(req); SAFE_FREE(uri); return cbuf; }