| /** @file |
| |
| A brief file description |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #pragma once |
| |
| /**************************************************************************** |
| * |
| * Rollback.h - Interface for class to allow rollback of configuration |
| * files |
| * |
| * |
| ****************************************************************************/ |
| |
| #include "tscore/ink_platform.h" |
| #include "tscore/ink_mutex.h" |
| #include "tscore/ink_assert.h" |
| #include "tscore/TextBuffer.h" |
| #include "tscore/List.h" |
| |
| class FileManager; |
| |
| #define ACTIVE_VERSION 0 |
| #define INVALID_VERSION -1 |
| |
| #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC |
| #define TS_ARCHIVE_STAT_MTIME(t) ((t).st_mtime * 1000000000 + (t).st_mtimespec.tv_nsec) |
| #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC |
| #define TS_ARCHIVE_STAT_MTIME(t) ((t).st_mtime * 1000000000 + (t).st_mtim.tv_nsec) |
| #else |
| #define TS_ARCHIVE_STAT_MTIME(t) ((t).st_mtime * 1000000000) |
| #endif |
| |
| typedef int version_t; |
| |
| enum RollBackCodes { |
| OK_ROLLBACK, |
| FILE_NOT_FOUND_ROLLBACK, |
| VERSION_NOT_CURRENT_ROLLBACK, |
| SYS_CALL_ERROR_ROLLBACK, |
| INVALID_VERSION_ROLLBACK |
| }; |
| |
| enum RollBackCheckType { |
| ROLLBACK_CHECK_AND_UPDATE, |
| ROLLBACK_CHECK_ONLY, |
| }; |
| |
| class ExpandingArray; |
| |
| // Stores info about a backup version |
| // Can be put in to List.h lists |
| struct versionInfo { |
| version_t version; |
| time_t modTime; |
| LINK(versionInfo, link); |
| }; |
| |
| // |
| // class Rollback |
| // |
| // public functions |
| // |
| // _ml functions assume the callee is handling locking issues |
| // via acquireLock() and releaseLock(). The non _ml |
| // simply grab the lock, call the corresponding _ml function, |
| // and then release the lock |
| // |
| // removeVersion(version_t ) - removes the specified version from the |
| // configuration directory |
| // |
| // revertToVersion(version_t) - rolls the active version to a new file |
| // The specified version of the file is copied to the active version |
| // |
| // getVersion(version_t version, TextBuffer** buffer, version_t) - |
| // creates a new TextBuffer that contains the contents of the specified |
| // version. CALLEE MUST DELETE the buffer |
| // |
| // updateVersion(TextBuffer* buf, version_t basedOn) - checks to |
| // if basedOn is the current version. If it is not, the update |
| // rejected. If it is current, the active file is versioned and |
| // the contents of buf become the new active file. newVersion tells us what |
| // the new version number should be. -1 means the next in sequence |
| // |
| // forceUpdate(TextBuffer* buf, version_t) - Does not check is the new version |
| // is based on the current version, which can lead to data loss. versions |
| // the active file and places the contents of buf into the active file |
| // |
| // getCurrentVersion() - returns the current version number. Unless the |
| // callee was acquired the fileAccessLock, the return value only represents |
| // a snap shot in time |
| // |
| // numberOfVersions() - returns the number of versions in the config dir. |
| // Unless the callee was acquired the fileAccessLock, the return value |
| // only represents a snap shot in time |
| // |
| // checkForUserUpdate() - compares the last known modification time |
| // of the active version of the file with that files current modification |
| // time. Returns true if the file has been chaged manually or false |
| // if it hasn't |
| // |
| // versionTimeStamp(version_t) - returns the modification time (mtime) |
| // of the version passed in. If the version is not foundl, -1 is |
| // returned |
| // |
| // findVersions(ExpandingArray* listNames) - scans the config directory for |
| // all versions of the file. If listNames is not NULL, pointers to versionInfo |
| // structures are inserted into it. If is the callee's responsibility |
| // to ats_free the versionInfo structures. They are allocated by ats_malloc |
| // |
| // private functions |
| // |
| // CURRENT_VERSION means the active version. The active version does not |
| // have _version appended to its name. All prior versions are stored |
| // as fileName_version. Calling file operations with CURRENT_VERSION |
| // and this->currentVersion have different meanings. this->currentVersion |
| // refers to a file with an _version which does not exist for the active |
| // version. |
| // |
| // findVersions() - scans the configuration directory and returns |
| // the highest version number encountered |
| // |
| // openFile(version_t version, int oflags) - a wrapper for open |
| // opens a file based on version number |
| // |
| // statFile(version_t, struct stat*) - a wrapper for stat that |
| // that stats the specified version |
| // |
| // createPathStr(version_t) - creates a string to the specified |
| // version of the file. CALLEE DELETES storage |
| // |
| // internalUpdate(TextBuffer*, version_t) - does the really work of the |
| // public update functions. newVersion tells us what the new |
| // version number should be. -1 means the next in sequence |
| |
| class Rollback |
| { |
| public: |
| // fileName_ should be rooted or a base file name. |
| Rollback(const char *fileName_, bool root_access_needed, Rollback *parentRollback = nullptr, unsigned flags = 0); |
| ~Rollback(); |
| |
| // Manual take out of lock required |
| void |
| acquireLock() |
| { |
| ink_mutex_acquire(&fileAccessLock); |
| }; |
| void |
| releaseLock() |
| { |
| ink_mutex_release(&fileAccessLock); |
| }; |
| RollBackCodes removeVersion_ml(version_t version); |
| RollBackCodes revertToVersion_ml(version_t version); |
| RollBackCodes getVersion_ml(version_t version, TextBuffer **buffer); |
| RollBackCodes updateVersion_ml(TextBuffer *buf, version_t basedOn, version_t newVersion = -1, bool notifyChange = true, |
| bool incVersion = true); |
| RollBackCodes forceUpdate_ml(TextBuffer *buf, version_t newVersion = -1); |
| version_t findVersions_ml(ExpandingArray *listNames); |
| version_t findVersions_ml(Queue<versionInfo> &q); |
| time_t versionTimeStamp_ml(version_t version); |
| version_t extractVersionInfo(ExpandingArray *listNames, const char *testFileName); |
| |
| // Automatically take out lock |
| bool checkForUserUpdate(RollBackCheckType); |
| RollBackCodes removeVersion(version_t version); |
| RollBackCodes revertToVersion(version_t version); |
| RollBackCodes getVersion(version_t version, TextBuffer **buffer); |
| RollBackCodes updateVersion(TextBuffer *buf, version_t basedOn, version_t newVersion = -1, bool notifyChange = true, |
| bool incVersion = true); |
| RollBackCodes forceUpdate(TextBuffer *buf, version_t newVersion = -1); |
| version_t findVersions(ExpandingArray *); |
| time_t versionTimeStamp(version_t version); |
| int statVersion(version_t, struct stat *buf); |
| bool setLastModifiedTime(); |
| |
| // Lock not necessary since these are only valid for a |
| // snap shot in time |
| version_t |
| getCurrentVersion() const |
| { |
| return currentVersion; |
| }; |
| int |
| numberOfVersions() const |
| { |
| return numVersions; |
| } |
| |
| // Not file based so no lock necessary |
| const char * |
| getBaseName() const |
| { |
| return fileBaseName; |
| } |
| const char * |
| getFileName() const |
| { |
| return fileName; |
| } |
| bool |
| isChildRollback() const |
| { |
| return parentRollback != nullptr; |
| } |
| Rollback * |
| getParentRollback() const |
| { |
| return parentRollback; |
| } |
| bool |
| isVersioned() const |
| { |
| return numberBackups > 0; |
| } |
| bool |
| rootAccessNeeded() const |
| { |
| return root_access_needed; |
| } |
| |
| FileManager *configFiles; // Manager to notify on an update. |
| |
| // noncopyable |
| Rollback(const Rollback &) = delete; |
| Rollback &operator=(const Rollback &) = delete; |
| |
| private: |
| int openFile(version_t version, int oflags, int *errnoPtr = nullptr); |
| int closeFile(int fd, bool callSync); |
| int statFile(version_t version, struct stat *buf); |
| char *createPathStr(version_t version); |
| RollBackCodes internalUpdate(TextBuffer *buf, version_t newVersion, bool notifyChange = true, bool incVersion = true); |
| ink_mutex fileAccessLock; |
| char *fileName; |
| char *fileBaseName; |
| size_t fileNameLen; |
| bool root_access_needed; |
| Rollback *parentRollback; |
| version_t currentVersion; |
| time_t fileLastModified; |
| int numVersions; |
| int numberBackups; |
| Queue<versionInfo> versionQ; // stores the backup version info |
| }; |
| |
| // qSort comptable function to sort versionInfo* |
| // based on version number |
| int versionCmp(const void *i1, const void *i2); |