void cmd_drop(int id){ snapshot* snapshot = getSnapshot(id); if(snapshot != NULL){ deleteSnapshot(snapshot); printf("ok\n"); return; } printf("no such snapshot\n"); }
void cmd_rollback(int id){ snapshot* rollbackSnapshot = getSnapshot(id); if(rollbackSnapshot != NULL){ snapshot* currentSnapshot = snapshot_head; while(currentSnapshot != rollbackSnapshot){ snapshot* nextSnapshot = currentSnapshot->next; deleteSnapshot(currentSnapshot); currentSnapshot = nextSnapshot; } cmd_checkout(id); }else{ printf("no such snapshot\n"); } }
int syncInit(int cfd, long long *tbytes) { char errmsg[ERRMSG_MAX] = {0}; SyncInit *syncinit; SyncInitResponse response = SYNC_INIT_RESPONSE__INIT; syncinit = (SyncInit *) recvMessage(cfd, SyncInitType, tbytes); if (syncinit == NULL) { errMsg(LOG_ERR, "Could not read initialization message from client."); return -1; } // initial checks // check resource (must match) if (strcmp(syncinit->resource, config.resource) != 0) { snprintf(errmsg, ERRMSG_MAX, "Received resource %s does not match." "local resource %s", syncinit->resource, config.resource); response.continue_ = 0; response.error_message = errmsg; sendMessage(cfd, SyncInitResponseType, &response); return -1; } // check sync-id char lastsyncid[SYNCID_MAX]; char lastsyncidpath[PATH_MAX]; char syncid[SYNCID_MAX]; char syncidpath[PATH_MAX]; // if we receive syncid, we already marked as successfully done // only sending confirmation has failed last time snprintf(lastsyncidpath, PATH_MAX, "%s/%s.syncid.last", config.logdir, config.resource); if (fileExists(lastsyncidpath) && (readSyncId(lastsyncid, lastsyncidpath, SYNCID_MAX) == 0)) { if (lastsyncid == syncinit->sync_id) { // send the confirmation, don't sync response.continue_ = 0; response.has_already_synced = 1; response.already_synced = 1; sendMessage(cfd, SyncInitResponseType, &response); return 0; // no files to be synchronized } } int errflag = 0; // if we can read syncid file, last sync did not finish properly // revert snapshot snprintf(syncidpath, PATH_MAX, "%s/%s.syncid", config.logdir, config.resource); if (fileExists(syncidpath) && (readSyncId(syncid, syncidpath, SYNCID_MAX) == 0)) { if (syncid == syncinit->sync_id) { // TODO: here we should support resume } // revert last snapshot, check for its existence is necessary, but // is done nevertheless if (fileExists(config.snapshot) == 1) { // do as one block, this should not fail, if yes, we are in trouble errMsg(LOG_INFO, "Reverting snapshot."); int ret = 0; ret = deleteSnapshot(config.rootdir); ret |= createSnapshot(config.snapshot, config.rootdir, 0); ret |= deleteSnapshot(config.snapshot); if (ret != 0) { errflag = 1; snprintf(errmsg, ERRMSG_MAX, "Reverting to last snapshot" "has failed."); } } } // create snapshot // snapshot might exists (if last time program crash before sync-id was // written or before it was deleted), but in this case we don't need to // revert it if (!errflag && fileExists(config.snapshot)) { errMsg(LOG_INFO, "Snapshot %s unexpectedly exists, deleting.", config.snapshot); if (deleteSnapshot(config.snapshot) == -1) { errMsg(LOG_ERR, "Could not delete snapshot %s", config.snapshot); errflag = 1; } } if (!errflag && (createSnapshot(config.rootdir, config.snapshot, 1) != 0)) { errMsg(LOG_ERR, "Could not create snapshot %s", config.snapshot); errflag = 1; } // write syncid if (!errflag && (writeSyncId(syncinit->sync_id, syncidpath) != 0)) { errMsg(LOG_ERR, "Could not write sync-id. Stopping."); errflag = 1; } // send response int ret; if (errflag) { response.continue_ = 0; snprintf(errmsg, ERRMSG_MAX, "Error in snapshot operation."); response.error_message = errmsg; ret = -1; } else { response.continue_ = 1; ret = syncinit->number_files; } sync_init__free_unpacked(syncinit, NULL); if (sendMessage(cfd, SyncInitResponseType, &response) == 0) return ret; else return -1; }
int handleClient(int cfd, struct sockaddr *claddr, socklen_t *addrlen) { long long tbytes = 0; // total number of transfered bytes char addrstr[IS_ADDR_STR_LEN]; errMsg(LOG_INFO, "Connection from %s", inetAddressStr(claddr, *addrlen, addrstr, IS_ADDR_STR_LEN)); // sync-init, return value is number of files int32_t nfiles; nfiles = syncInit(cfd, &tbytes); if (nfiles == -1) return -1; errMsg(LOG_INFO, "Number of files to synchronize: %d", nfiles); // outer loop: files, inner loop: chunks for (int i = 0; i < nfiles; i++) { FileChunk *chunk; int fd = -1; // we are guaranteed to get at least one chunk for each file chunk = (FileChunk *) recvMessage(cfd, FileChunkType, &tbytes); if (chunk == NULL) { errMsg(LOG_ERR, "Could not read message from client."); return -1; } for (;;) { for (int k = 0; k < chunk->n_ops; k++) { // TODO // in case of a failure inform client to do an rsync based sync handleGenericOperation(&fd, chunk->relative_path, chunk->ops[k]); } if (chunk->last_chunk == 1) { file_chunk__free_unpacked(chunk, NULL); break; } else { file_chunk__free_unpacked(chunk, NULL); chunk = (FileChunk *) recvMessage(cfd, FileChunkType, &tbytes); if (chunk == NULL) { errMsg(LOG_ERR, "Could not read message from client."); return -1; } } } if (fd != -1) { if (close(fd) == -1) errMsg(LOG_WARNING, "Could not close file."); } } errMsg(LOG_INFO, "Received bytes: %lld", tbytes); // transfer was successful, we can delete snapshot (created in syncInit()) if (deleteSnapshot(config.snapshot) == -1) { errMsg(LOG_ERR, "Could not delete snapshot %s", config.snapshot); close(cfd); return -1; } // rename resource.syncid to resource.syncid.last char lastsyncidpath[PATH_MAX]; char syncidpath[PATH_MAX]; snprintf(lastsyncidpath, PATH_MAX, "%s/%s.syncid.last", config.logdir, config.resource); snprintf(syncidpath, PATH_MAX, "%s/%s.syncid", config.logdir, config.resource); if (rename(syncidpath, lastsyncidpath) == -1) { errnoMsg(LOG_CRIT, "Could not rename sync-id file to sync-id.last."); close(cfd); return -1; } // and finally send confirmation to client SyncFinish conf = SYNC_FINISH__INIT; conf.has_transferred_bytes = 1; conf.transferred_bytes = (uint64_t) tbytes; if (sendMessage(cfd, SyncFinishType, &conf) != 0) { close(cfd); return -1; } if (close(cfd) == -1) errMsg(LOG_WARNING, "Could not close socket."); return 0; }
int synchronize(void) { int pidfd; char pidpath[PATH_MAX]; int logfd; char logpath[PATH_MAX]; int newsync = 0; // make sure, that there isn't another client process for this resource // already running snprintf(pidpath, PATH_MAX, "/var/run/syncedfs/client/%s.pid", config.resource); pidfd = createPidFile(config.ident, pidpath, 0); if (pidfd == -1) { errMsg(LOG_ERR, "Could not create pid file %s, Exiting sync.", pidpath); return -1; } // if sync log does not exist, switch log snprintf(logpath, PATH_MAX, "%s/%s.sync", config.logdir, config.resource); errMsg(LOG_INFO, "logpath: %s", logpath); logfd = open(logpath, O_RDONLY); if (logfd == -1) { if (switchLog() != 0) { errMsg(LOG_ERR, "Could not switch log file. Stopping."); return -1; } logfd = open(logpath, O_RDONLY); if (logfd == -1) { errnoMsg(LOG_ERR, "Could not open log file %s", logpath); return -1; } newsync = 1; } // sync-id char id[SYNCID_MAX]; char idpath[PATH_MAX]; snprintf(idpath, PATH_MAX, "%s/%s.id", config.logdir, config.resource); // second part of the condition covers weird states after crash etc. if (newsync == 1 || readSyncId(id, idpath, SYNCID_MAX) != 0) { if (generateSyncId(id, SYNCID_MAX) != 0) { errMsg(LOG_ERR, "Could not get sync-id. Stopping."); return -1; } if (writeSyncId(id, idpath) != 0) { errMsg(LOG_ERR, "Could not write sync-id. Stopping."); return -1; } } // create snapshot if (newsync || !fileExists(config.snapshot)) { if (createSnapshot(config.rootdir, config.snapshot, 1) == -1) { errMsg(LOG_ERR, "Could not create snapshot of %s to %s Stopping.", config.rootdir, config.snapshot); return -1; } } // load log if (loadLog(logfd) != 0) { errMsg(LOG_ERR, "Could not load log %s", logpath); return -1; } // transfer changes if (transfer(config.host, config.port) == -1) { errMsg(LOG_ERR, "Error in transfer. Exiting sync."); // in case of failure only delete pid file if (deletePidFile(pidfd, pidpath) == -1) errExit(LOG_ERR, "Deleting PID file '%s'", pidpath); return -1; } // delete snapshot if (deleteSnapshot(config.snapshot) == -1) errMsg(LOG_ERR, "Could not delete snapshot %s", config.snapshot); // delete syncid if (unlink(idpath) == -1) errExit(LOG_ERR, "Deleting sync-id file '%s'", idpath); // delete sync log close(logfd); if (unlink(logpath) == -1) errExit(LOG_ERR, "Deleting log file '%s'", logpath); // delete pid file if (deletePidFile(pidfd, pidpath) == -1) errExit(LOG_ERR, "Deleting PID file '%s'", pidpath); return 0; }