add .gitignore
[swift-upb.git] / hashtree.cpp
index 9665cff..783b900 100644 (file)
 #include <fcntl.h>
 #include "compat.h"
 
-using namespace p2tp;
+#ifdef _WIN32
+#define OPENFLAGS         O_RDWR|O_CREAT|_O_BINARY
+#else
+#define OPENFLAGS         O_RDWR|O_CREAT
+#endif
+
+
+using namespace swift;
 
 #define HASHSZ 20
 const size_t Sha1Hash::SIZE = HASHSZ;
@@ -29,29 +36,32 @@ void SHA1 (const void *data, size_t length, unsigned char *hash) {
 }
 
 Sha1Hash::Sha1Hash(const Sha1Hash& left, const Sha1Hash& right) {
-       char data[HASHSZ*2];
-       memcpy(data,left.bits,SIZE);
-       memcpy(data+SIZE,right.bits,SIZE);
-       SHA1((unsigned char*)data,SIZE*2,bits);
+    char data[HASHSZ*2];
+    memcpy(data,left.bits,SIZE);
+    memcpy(data+SIZE,right.bits,SIZE);
+    SHA1((unsigned char*)data,SIZE*2,bits);
 }
 
 Sha1Hash::Sha1Hash(const char* data, size_t length) {
     if (length==-1)
         length = strlen(data);
-       SHA1((unsigned char*)data,length,bits);
+    SHA1((unsigned char*)data,length,bits);
 }
 
 Sha1Hash::Sha1Hash(const uint8_t* data, size_t length) {
-       SHA1(data,length,bits);
+    SHA1(data,length,bits);
 }
 
 Sha1Hash::Sha1Hash(bool hex, const char* hash) {
-       if (hex) {
+    if (hex) {
         char hx[3]; hx[2]=0;
         int val;
         for(int i=0; i<SIZE; i++) {
             strncpy(hx,hash+i*2,2);
-            sscanf(hx, "%x", &val);
+            if (sscanf(hx, "%x", &val)!=1) {
+                memset(bits,0,20);
+                return;
+            }
             bits[i] = val;
         }
         assert(this->hex()==std::string(hash));
@@ -59,11 +69,11 @@ Sha1Hash::Sha1Hash(bool hex, const char* hash) {
         memcpy(bits,hash,SIZE);
 }
 
-std::string    Sha1Hash::hex() const {
-       char hex[HASHSZ*2+1];
-       for(int i=0; i<HASHSZ; i++)
-               sprintf(hex+i*2, "%02x", (int)(unsigned char)bits[i]);
-       return std::string(hex,HASHSZ*2);
+std::string    Sha1Hash::hex() const {
+    char hex[HASHSZ*2+1];
+    for(int i=0; i<HASHSZ; i++)
+        sprintf(hex+i*2, "%02x", (int)(unsigned char)bits[i]);
+    return std::string(hex,HASHSZ*2);
 }
 
 
@@ -76,18 +86,24 @@ root_hash_(root_hash), fd_(0), hash_fd_(0), data_recheck_(true),
 peak_count_(0), hashes_(NULL), size_(0), sizek_(0),
 complete_(0), completek_(0)
 {
-       fd_ = open(filename,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
-       if (fd_<0)
+    fd_ = open(filename,OPENFLAGS,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+    if (fd_<0) {
+        fd_ = 0;
+        print_error("cannot open the file");
         return;
+    }
     char hfn[1024] = "";
     if (!hash_filename) {
         strcat(hfn, filename);
         strcat(hfn, ".mhash");
     } else
         strcpy(hfn,hash_filename);
-    hash_fd_ = open(hfn,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
-    if (hash_fd_<0)
+    hash_fd_ = open(hfn,OPENFLAGS,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+    if (hash_fd_<0) {
+        hash_fd_ = 0;
+        print_error("cannot open hash file");
         return;
+    }
     if (root_hash_==Sha1Hash::ZERO) { // fresh submit, hash it
         assert(file_size(fd_));
         Submit();
@@ -99,7 +115,7 @@ complete_(0), completek_(0)
 
 void            HashTree::Submit () {
     size_ = file_size(fd_);
-       sizek_ = (size_>>10) + ((size_&1023) ? 1 : 0);
+    sizek_ = (size_ + 1023) >> 10;
     peak_count_ = bin64_t::peaks(sizek_,peaks_);
     int hashes_size = Sha1Hash::SIZE*sizek_*2;
     file_resize(hash_fd_,hashes_size);
@@ -139,7 +155,7 @@ void            HashTree::Submit () {
  for some optimizations. */
 void            HashTree::RecoverProgress () {
     size_t size = file_size(fd_);
-       size_t sizek = (size>>10) + ((size&1023) ? 1 : 0);
+    size_t sizek = (size + 1023) >> 10;
     bin64_t peaks[64];
     int peak_count = bin64_t::peaks(sizek,peaks);
     for(int i=0; i<peak_count; i++) {
@@ -162,14 +178,18 @@ void            HashTree::RecoverProgress () {
         if (hashes_[pos]==Sha1Hash::ZERO)
             continue;
         size_t rd = read(fd_,buf,1<<10);
-        assert(rd==(1<<10) || p==packet_size()-1);
-        if (rd==(1<<10) && !memcmp(buf, zeros, rd) && hashes_[pos]!=kilo_zero)
+        if (rd!=(1<<10) && p!=packet_size()-1)
+            break;
+        if (rd==(1<<10) && !memcmp(buf, zeros, rd) &&
+                hashes_[pos]!=kilo_zero) // FIXME
             continue;
         if ( data_recheck_ && !OfferHash(pos, Sha1Hash(buf,rd)) )
             continue;
         ack_out_.set(pos);
         completek_++;
         complete_+=rd;
+        if (rd!=(1<<10) && p==packet_size()-1)
+            size_ = ((sizek_-1)<<10) + rd;
     }
 }
 
@@ -196,7 +216,7 @@ bool            HashTree::OfferPeakHash (bin64_t pos, const Sha1Hash& hash) {
 
     size_ = sizek_<<10;
     completek_ = complete_ = 0;
-       sizek_ = (size_>>10) + ((size_&1023) ? 1 : 0);
+    sizek_ = (size_ + 1023) >> 10;
 
     size_t cur_size = file_size(fd_);
     if ( cur_size<=(sizek_-1)<<10  || cur_size>sizek_<<10 )
@@ -225,23 +245,22 @@ bool            HashTree::OfferPeakHash (bin64_t pos, const Sha1Hash& hash) {
 
 
 Sha1Hash        HashTree::DeriveRoot () {
-       int c = peak_count_-1;
-       bin64_t p = peaks_[c];
-       Sha1Hash hash = peak_hashes_[c];
-       c--;
-       while (p!=bin64_t::ALL) {
-               if (p.is_left()) {
-                       p = p.parent();
-                       hash = Sha1Hash(hash,Sha1Hash::ZERO);
-               } else {
-                       if (c<0 || peaks_[c]!=p.sibling())
-                               return Sha1Hash::ZERO;
-                       hash = Sha1Hash(peak_hashes_[c],hash);
-                       p = p.parent();
-                       c--;
-               }
-        //dprintf("p %lli %s\n",(uint64_t)p,hash.hex().c_str());
-       }
+    int c = peak_count_-1;
+    bin64_t p = peaks_[c];
+    Sha1Hash hash = peak_hashes_[c];
+    c--;
+    while (p!=bin64_t::ALL) {
+        if (p.is_left()) {
+            p = p.parent();
+            hash = Sha1Hash(hash,Sha1Hash::ZERO);
+        } else {
+            if (c<0 || peaks_[c]!=p.sibling())
+                return Sha1Hash::ZERO;
+            hash = Sha1Hash(peak_hashes_[c],hash);
+            p = p.parent();
+            c--;
+        }
+    }
     return hash;
 }
 
@@ -262,21 +281,21 @@ bin64_t         HashTree::peak_for (bin64_t pos) const {
 
 
 bool            HashTree::OfferHash (bin64_t pos, const Sha1Hash& hash) {
-       if (!size_)  // only peak hashes are accepted at this point
-               return OfferPeakHash(pos,hash);
+    if (!size_)  // only peak hashes are accepted at this point
+        return OfferPeakHash(pos,hash);
     bin64_t peak = peak_for(pos);
     if (peak==bin64_t::NONE)
         return false;
     if (peak==pos)
         return hash == hashes_[pos];
-    if (ack_out_.get(pos.parent())!=bins::EMPTY)
+    if (ack_out_.get(pos.parent())!=binmap_t::EMPTY)
         return hash==hashes_[pos]; // have this hash already, even accptd data
-       hashes_[pos] = hash;
+    hashes_[pos] = hash;
     if (!pos.is_base())
         return false; // who cares?
     bin64_t p = pos;
     Sha1Hash uphash = hash;
-    while ( p!=peak && ack_out_.get(p)==bins::EMPTY ) {
+    while ( p!=peak && ack_out_.get(p)==binmap_t::EMPTY ) {
         hashes_[p] = uphash;
         p = p.parent();
         uphash = Sha1Hash(hashes_[p.left()],hashes_[p.right()]) ;
@@ -292,17 +311,20 @@ bool            HashTree::OfferData (bin64_t pos, const char* data, size_t lengt
         return false;
     if (length<1024 && pos!=bin64_t(0,sizek_-1))
         return false;
-    if (ack_out_.get(pos)==bins::FILLED)
+    if (ack_out_.get(pos)==binmap_t::FILLED)
         return true; // to set data_in_
     bin64_t peak = peak_for(pos);
     if (peak==bin64_t::NONE)
         return false;
 
-    if (!OfferHash(pos, Sha1Hash(data,length)))
+    Sha1Hash data_hash(data,length);
+    if (!OfferHash(pos, data_hash)) {
+        //printf("invalid hash for %s: %s\n",pos.str(),data_hash.hex().c_str()); // paranoid
         return false;
+    }
 
     //printf("g %lli %s\n",(uint64_t)pos,hash.hex().c_str());
-    ack_out_.set(pos,bins::FILLED);
+    ack_out_.set(pos,binmap_t::FILLED);
     pwrite(fd_,data,length,pos.base_offset()<<10);
     complete_ += length;
     completek_++;
@@ -328,5 +350,7 @@ HashTree::~HashTree () {
         memory_unmap(hash_fd_, hashes_, sizek_*2*sizeof(Sha1Hash));
     if (fd_)
         close(fd_);
+    if (hash_fd_)
+        close(hash_fd_);
 }