2016-08-23 01:40:56 +03:00
|
|
|
// manifest.cpp - c++ implementation of a single manifest
|
|
|
|
//
|
|
|
|
// Copyright 2016 Facebook, Inc.
|
|
|
|
//
|
|
|
|
// This software may be used and distributed according to the terms of the
|
|
|
|
// GNU General Public License version 2 or any later version.
|
|
|
|
//
|
|
|
|
// no-check-code
|
|
|
|
|
2017-08-23 05:09:07 +03:00
|
|
|
#include <sha1dc/sha1.h>
|
sha1: switch to new implementation
Summary:
This diff changes our code to use the new SHA1 library. See the previous diff
for why we do this.
Test Plan:
Run related tests manually:
```
$ make local PYTHON=python2
$ rt test-remotefilelog-*.t
.........................
# Ran 25 tests, 0 skipped, 0 warned, 0 failed.
$ rt test-treemanifest*.t
........
# Ran 8 tests, 0 skipped, 0 warned, 0 failed.
$ rt test-fastmanifest*.t
.........
# Ran 9 tests, 0 skipped, 0 warned, 0 failed.
```
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D4945025
Signature: t1:4945025:1493154873:844e55a51ab250354fc08163e0949eed47b0a861
2017-04-26 00:53:32 +03:00
|
|
|
|
2016-08-23 01:40:56 +03:00
|
|
|
#include "manifest.h"
|
|
|
|
|
2017-04-20 07:14:03 +03:00
|
|
|
Manifest::Manifest(ConstantStringRef &rawobj, const char *node) :
|
2016-10-15 02:01:12 +03:00
|
|
|
_rawobj(rawobj),
|
2016-10-15 02:01:12 +03:00
|
|
|
_refcount(0),
|
|
|
|
_mutable(false) {
|
2017-04-26 01:44:55 +03:00
|
|
|
const char *parseptr = _rawobj.content();
|
|
|
|
const char *endptr = parseptr + _rawobj.size();
|
2016-08-23 01:40:56 +03:00
|
|
|
|
|
|
|
while (parseptr < endptr) {
|
2016-09-19 23:25:34 +03:00
|
|
|
ManifestEntry entry;
|
|
|
|
parseptr = entry.initialize(parseptr);
|
2016-08-23 01:40:56 +03:00
|
|
|
entries.push_back(entry);
|
|
|
|
}
|
2017-04-20 07:14:03 +03:00
|
|
|
|
|
|
|
if (!node) {
|
|
|
|
throw std::logic_error("null node passed to manifest");
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(this->_node, node, BIN_NODE_SIZE);
|
2016-08-23 01:40:56 +03:00
|
|
|
}
|
|
|
|
|
2016-10-15 02:01:12 +03:00
|
|
|
ManifestPtr Manifest::copy() {
|
|
|
|
ManifestPtr copied(new Manifest());
|
2016-09-19 23:25:34 +03:00
|
|
|
copied->_rawobj = this->_rawobj;
|
2016-09-12 21:44:47 +03:00
|
|
|
|
|
|
|
for (std::list<ManifestEntry>::iterator thisIter = this->entries.begin();
|
|
|
|
thisIter != this->entries.end();
|
|
|
|
thisIter ++) {
|
2016-09-19 23:25:34 +03:00
|
|
|
copied->addChild(copied->entries.end(), &(*thisIter));
|
2016-09-12 21:44:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return copied;
|
|
|
|
}
|
|
|
|
|
2016-08-23 01:47:16 +03:00
|
|
|
ManifestIterator Manifest::getIterator() {
|
2016-08-23 01:40:56 +03:00
|
|
|
return ManifestIterator(this->entries.begin(), this->entries.end());
|
|
|
|
}
|
|
|
|
|
2016-09-18 23:42:09 +03:00
|
|
|
SortedManifestIterator Manifest::getSortedIterator() {
|
|
|
|
// populate the sorted list if it's not present.
|
|
|
|
if (this->entries.size() != this->mercurialSortedEntries.size()) {
|
|
|
|
this->mercurialSortedEntries.clear();
|
|
|
|
|
|
|
|
for (std::list<ManifestEntry>::iterator iterator = this->entries.begin();
|
|
|
|
iterator != this->entries.end();
|
|
|
|
iterator ++) {
|
|
|
|
this->mercurialSortedEntries.push_back(&(*iterator));
|
|
|
|
}
|
|
|
|
|
|
|
|
this->mercurialSortedEntries.sort(ManifestEntry::compareMercurialOrder);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SortedManifestIterator(
|
|
|
|
this->mercurialSortedEntries.begin(),
|
|
|
|
this->mercurialSortedEntries.end());
|
|
|
|
}
|
|
|
|
|
2016-08-23 01:41:52 +03:00
|
|
|
/**
|
|
|
|
* Returns an iterator correctly positioned for a child of a given
|
|
|
|
* filename. If a child with the same name already exists, *exacthit will
|
|
|
|
* be set to true. Otherwise, it will be set to false.
|
|
|
|
*/
|
|
|
|
std::list<ManifestEntry>::iterator Manifest::findChild(
|
2016-10-15 02:01:12 +03:00
|
|
|
const char *filename, const size_t filenamelen, FindResultType resulttype,
|
2016-08-23 01:41:52 +03:00
|
|
|
bool *exacthit) {
|
|
|
|
for (std::list<ManifestEntry>::iterator iter = this->entries.begin();
|
|
|
|
iter != this->entries.end();
|
|
|
|
iter ++) {
|
2016-08-26 23:49:17 +03:00
|
|
|
size_t minlen = filenamelen < iter->filenamelen ?
|
|
|
|
filenamelen : iter->filenamelen;
|
|
|
|
|
2016-08-23 01:41:52 +03:00
|
|
|
// continue until we are lexicographically <= than the current location.
|
2016-08-26 23:49:17 +03:00
|
|
|
int cmp = strncmp(filename, iter->filename, minlen);
|
2016-09-18 23:44:50 +03:00
|
|
|
bool current_isdir = iter->isdirectory();
|
2016-08-26 23:49:17 +03:00
|
|
|
if (cmp == 0 && filenamelen == iter->filenamelen) {
|
2016-10-15 02:01:12 +03:00
|
|
|
if ((current_isdir && resulttype != RESULT_FILE) ||
|
|
|
|
(!current_isdir && resulttype != RESULT_DIRECTORY)) {
|
2016-09-18 23:44:50 +03:00
|
|
|
*exacthit = true;
|
|
|
|
return iter;
|
|
|
|
} else if (current_isdir) {
|
|
|
|
// the current entry we're looking at is a directory, but we want to
|
|
|
|
// insert a file. we need to move to the next entry.
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
*exacthit = false;
|
|
|
|
return iter;
|
|
|
|
}
|
2016-08-26 23:49:17 +03:00
|
|
|
} else if (cmp > 0 ||
|
|
|
|
(cmp == 0 && filenamelen > iter->filenamelen)) {
|
|
|
|
continue;
|
2016-08-23 01:41:52 +03:00
|
|
|
} else {
|
|
|
|
*exacthit = false;
|
|
|
|
return iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*exacthit = false;
|
|
|
|
return this->entries.end();
|
|
|
|
}
|
|
|
|
|
2016-09-06 22:39:07 +03:00
|
|
|
ManifestEntry *Manifest::addChild(std::list<ManifestEntry>::iterator iterator,
|
|
|
|
const char *filename, const size_t filenamelen, const char *node,
|
2016-09-18 23:40:14 +03:00
|
|
|
const char *flag) {
|
2016-10-15 02:01:12 +03:00
|
|
|
if (!this->isMutable()) {
|
|
|
|
throw std::logic_error("attempting to mutate immutable Manifest");
|
|
|
|
}
|
|
|
|
|
2016-08-26 23:49:17 +03:00
|
|
|
ManifestEntry entry;
|
2016-08-23 01:41:52 +03:00
|
|
|
this->entries.insert(iterator, entry);
|
|
|
|
|
|
|
|
// move back to the element we just added.
|
|
|
|
--iterator;
|
|
|
|
|
|
|
|
// return a reference to the element we added, not the one on the stack.
|
2016-08-26 23:49:17 +03:00
|
|
|
ManifestEntry *result = &(*iterator);
|
|
|
|
|
2016-09-06 22:39:07 +03:00
|
|
|
result->initialize(filename, filenamelen, node, flag);
|
2016-08-26 23:49:17 +03:00
|
|
|
|
2016-09-18 23:42:09 +03:00
|
|
|
// invalidate the mercurial-ordered list of entries
|
|
|
|
this->mercurialSortedEntries.clear();
|
|
|
|
|
2016-08-26 23:49:17 +03:00
|
|
|
return result;
|
2016-08-23 01:41:52 +03:00
|
|
|
}
|
|
|
|
|
2016-09-12 21:44:47 +03:00
|
|
|
ManifestEntry *Manifest::addChild(std::list<ManifestEntry>::iterator iterator,
|
|
|
|
ManifestEntry *otherChild) {
|
2016-10-15 02:01:12 +03:00
|
|
|
if (!this->isMutable()) {
|
|
|
|
throw std::logic_error("attempting to mutate immutable Manifest");
|
|
|
|
}
|
|
|
|
|
2016-09-12 21:44:47 +03:00
|
|
|
ManifestEntry entry;
|
2016-09-19 23:25:34 +03:00
|
|
|
iterator = this->entries.insert(iterator, entry);
|
2016-09-12 21:44:47 +03:00
|
|
|
|
|
|
|
// return a reference to the element we added, not the one on the stack.
|
|
|
|
ManifestEntry *result = &(*iterator);
|
|
|
|
|
|
|
|
result->initialize(otherChild);
|
|
|
|
|
2016-09-18 23:42:09 +03:00
|
|
|
// invalidate the mercurial-ordered list of entries
|
|
|
|
this->mercurialSortedEntries.clear();
|
|
|
|
|
2016-09-12 21:44:47 +03:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-08-23 01:40:56 +03:00
|
|
|
ManifestIterator::ManifestIterator(
|
2016-08-23 01:47:16 +03:00
|
|
|
std::list<ManifestEntry>::iterator iterator,
|
2016-08-23 01:40:56 +03:00
|
|
|
std::list<ManifestEntry>::const_iterator end) :
|
|
|
|
iterator(iterator), end(end) {
|
|
|
|
}
|
|
|
|
|
2016-08-23 01:47:31 +03:00
|
|
|
ManifestEntry *ManifestIterator::next() {
|
2016-08-23 01:40:56 +03:00
|
|
|
if (this->isfinished()) {
|
2016-08-23 01:47:31 +03:00
|
|
|
return NULL;
|
2016-08-23 01:40:56 +03:00
|
|
|
}
|
|
|
|
|
2016-08-23 01:47:31 +03:00
|
|
|
ManifestEntry *result = &(*this->iterator);
|
|
|
|
this->iterator ++;
|
2016-08-23 01:40:56 +03:00
|
|
|
|
2016-08-23 01:47:31 +03:00
|
|
|
return result;
|
2016-08-23 01:40:56 +03:00
|
|
|
}
|
|
|
|
|
2016-08-23 01:47:16 +03:00
|
|
|
ManifestEntry *ManifestIterator::currentvalue() const {
|
2016-08-23 01:40:56 +03:00
|
|
|
if (this->isfinished()) {
|
|
|
|
throw std::logic_error("iterator has no current value");
|
|
|
|
}
|
|
|
|
|
2016-08-23 01:47:16 +03:00
|
|
|
return &(*iterator);
|
2016-08-23 01:40:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ManifestIterator::isfinished() const {
|
|
|
|
return iterator == end;
|
|
|
|
}
|
2016-09-12 21:44:59 +03:00
|
|
|
|
2016-09-18 23:42:09 +03:00
|
|
|
SortedManifestIterator::SortedManifestIterator(
|
|
|
|
std::list<ManifestEntry *>::iterator iterator,
|
|
|
|
std::list<ManifestEntry *>::const_iterator end) :
|
|
|
|
iterator(iterator),
|
|
|
|
end(end) {
|
|
|
|
}
|
|
|
|
|
|
|
|
ManifestEntry *SortedManifestIterator::next() {
|
|
|
|
if (this->isfinished()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ManifestEntry *result = *this->iterator;
|
|
|
|
this->iterator ++;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
ManifestEntry *SortedManifestIterator::currentvalue() const {
|
|
|
|
if (this->isfinished()) {
|
|
|
|
throw std::logic_error("iterator has no current value");
|
|
|
|
}
|
|
|
|
|
|
|
|
return *iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SortedManifestIterator::isfinished() const {
|
|
|
|
return iterator == end;
|
|
|
|
}
|
|
|
|
|
2016-09-12 21:44:59 +03:00
|
|
|
void Manifest::serialize(std::string &result) {
|
|
|
|
result.erase();
|
|
|
|
result.reserve(16 * 1024 * 1024);
|
|
|
|
ManifestIterator iterator = this->getIterator();
|
|
|
|
ManifestEntry *entry;
|
|
|
|
while ((entry = iterator.next()) != NULL) {
|
|
|
|
result.append(entry->filename, entry->filenamelen);
|
2016-09-19 23:25:34 +03:00
|
|
|
result.append("\0", 1);
|
2017-04-20 07:14:04 +03:00
|
|
|
result.append(entry->node ? entry->node : HEXNULLID, HEX_NODE_SIZE);
|
2016-09-12 21:44:59 +03:00
|
|
|
if (entry->flag) {
|
2016-09-19 23:25:34 +03:00
|
|
|
result.append(entry->flag, 1);
|
2016-09-12 21:44:59 +03:00
|
|
|
}
|
2016-09-19 23:25:34 +03:00
|
|
|
result.append("\n", 1);
|
2016-09-12 21:44:59 +03:00
|
|
|
}
|
|
|
|
}
|
2016-09-19 23:25:34 +03:00
|
|
|
|
|
|
|
void Manifest::computeNode(const char *p1, const char *p2, char *result) {
|
|
|
|
std::string content;
|
|
|
|
this->serialize(content);
|
|
|
|
|
sha1: switch to new implementation
Summary:
This diff changes our code to use the new SHA1 library. See the previous diff
for why we do this.
Test Plan:
Run related tests manually:
```
$ make local PYTHON=python2
$ rt test-remotefilelog-*.t
.........................
# Ran 25 tests, 0 skipped, 0 warned, 0 failed.
$ rt test-treemanifest*.t
........
# Ran 8 tests, 0 skipped, 0 warned, 0 failed.
$ rt test-fastmanifest*.t
.........
# Ran 9 tests, 0 skipped, 0 warned, 0 failed.
```
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D4945025
Signature: t1:4945025:1493154873:844e55a51ab250354fc08163e0949eed47b0a861
2017-04-26 00:53:32 +03:00
|
|
|
SHA1_CTX ctx;
|
|
|
|
SHA1DCInit(&ctx);
|
2016-09-19 23:25:34 +03:00
|
|
|
|
2016-11-30 02:37:58 +03:00
|
|
|
if (memcmp(p1, p2, BIN_NODE_SIZE) == -1) {
|
2017-04-26 06:21:14 +03:00
|
|
|
SHA1DCUpdate(&ctx, (const unsigned char *) p1, BIN_NODE_SIZE);
|
|
|
|
SHA1DCUpdate(&ctx, (const unsigned char *) p2, BIN_NODE_SIZE);
|
2016-11-30 02:37:58 +03:00
|
|
|
} else {
|
2017-04-26 06:21:14 +03:00
|
|
|
SHA1DCUpdate(&ctx, (const unsigned char *)p2, BIN_NODE_SIZE);
|
|
|
|
SHA1DCUpdate(&ctx, (const unsigned char *)p1, BIN_NODE_SIZE);
|
2016-11-30 02:37:58 +03:00
|
|
|
}
|
2017-04-26 06:21:14 +03:00
|
|
|
SHA1DCUpdate(&ctx, (const unsigned char *)content.c_str(), content.size());
|
2016-09-19 23:25:34 +03:00
|
|
|
|
sha1: switch to new implementation
Summary:
This diff changes our code to use the new SHA1 library. See the previous diff
for why we do this.
Test Plan:
Run related tests manually:
```
$ make local PYTHON=python2
$ rt test-remotefilelog-*.t
.........................
# Ran 25 tests, 0 skipped, 0 warned, 0 failed.
$ rt test-treemanifest*.t
........
# Ran 8 tests, 0 skipped, 0 warned, 0 failed.
$ rt test-fastmanifest*.t
.........
# Ran 9 tests, 0 skipped, 0 warned, 0 failed.
```
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D4945025
Signature: t1:4945025:1493154873:844e55a51ab250354fc08163e0949eed47b0a861
2017-04-26 00:53:32 +03:00
|
|
|
SHA1DCFinal((unsigned char*)result, &ctx);
|
2016-09-19 23:25:34 +03:00
|
|
|
}
|
2016-10-15 02:01:12 +03:00
|
|
|
|
2016-10-15 02:01:12 +03:00
|
|
|
ManifestPtr::ManifestPtr() :
|
|
|
|
manifest(NULL) {
|
|
|
|
}
|
|
|
|
|
2016-10-15 02:01:12 +03:00
|
|
|
ManifestPtr::ManifestPtr(Manifest *manifest) :
|
|
|
|
manifest(manifest) {
|
|
|
|
if (!manifest) {
|
|
|
|
throw std::logic_error("passed NULL manifest pointer");
|
|
|
|
}
|
|
|
|
this->manifest->incref();
|
|
|
|
}
|
|
|
|
|
|
|
|
ManifestPtr::ManifestPtr(const ManifestPtr &other) :
|
|
|
|
manifest(other.manifest) {
|
2016-10-15 02:01:12 +03:00
|
|
|
if (this->manifest) {
|
|
|
|
this->manifest->incref();
|
|
|
|
}
|
2016-10-15 02:01:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
ManifestPtr::~ManifestPtr() {
|
2016-10-15 02:01:12 +03:00
|
|
|
if (this->manifest && this->manifest->decref() == 0) {
|
2016-10-15 02:01:12 +03:00
|
|
|
delete(this->manifest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ManifestPtr& ManifestPtr::operator= (const ManifestPtr& other) {
|
2016-10-15 02:01:12 +03:00
|
|
|
if (this->manifest) {
|
|
|
|
this->manifest->decref();
|
|
|
|
}
|
2016-10-15 02:01:12 +03:00
|
|
|
this->manifest = other.manifest;
|
2016-10-15 02:01:12 +03:00
|
|
|
if (this->manifest) {
|
|
|
|
this->manifest->incref();
|
|
|
|
}
|
2016-10-15 02:01:12 +03:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
ManifestPtr::operator Manifest* () const {
|
|
|
|
return this->manifest;
|
|
|
|
}
|
|
|
|
|
2016-10-15 02:01:12 +03:00
|
|
|
Manifest *ManifestPtr::operator-> () {
|
|
|
|
return this->manifest;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ManifestPtr::isnull() const {
|
|
|
|
return this->manifest == NULL;
|
|
|
|
}
|
|
|
|
|
2016-10-15 02:01:12 +03:00
|
|
|
void Manifest::incref() {
|
|
|
|
this->_refcount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t Manifest::decref() {
|
|
|
|
this->_refcount--;
|
|
|
|
return this->_refcount;
|
|
|
|
}
|
2016-10-15 02:01:12 +03:00
|
|
|
|
|
|
|
bool Manifest::isMutable() const {
|
|
|
|
return this->_mutable;
|
|
|
|
}
|
|
|
|
|
2017-04-20 07:14:03 +03:00
|
|
|
void Manifest::markPermanent(const char *p1, const char *p2, ManifestEntry *entry) {
|
2017-04-20 07:14:03 +03:00
|
|
|
if (!this->isMutable()) {
|
|
|
|
throw std::logic_error("attempting to double mark manifest immutable");
|
|
|
|
}
|
|
|
|
this->_mutable = false;
|
|
|
|
this->computeNode(p1, p2, this->_node);
|
2017-04-20 07:14:03 +03:00
|
|
|
if (entry) {
|
|
|
|
entry->updatebinnode(this->_node, MANIFEST_DIRECTORY_FLAGPTR);
|
|
|
|
}
|
2017-04-20 07:14:03 +03:00
|
|
|
}
|
|
|
|
|
2017-04-20 07:14:03 +03:00
|
|
|
void Manifest::markPermanent(const char *node, ManifestEntry *entry) {
|
2017-04-20 07:14:03 +03:00
|
|
|
if (!this->isMutable()) {
|
|
|
|
throw std::logic_error("attempting to double mark manifest immutable");
|
|
|
|
}
|
2016-10-15 02:01:12 +03:00
|
|
|
this->_mutable = false;
|
2017-04-20 07:14:03 +03:00
|
|
|
memcpy(this->_node, node, BIN_NODE_SIZE);
|
2017-04-20 07:14:03 +03:00
|
|
|
if (entry) {
|
|
|
|
entry->updatebinnode(this->_node, MANIFEST_DIRECTORY_FLAGPTR);
|
|
|
|
}
|
2016-10-15 02:01:12 +03:00
|
|
|
}
|