5 * Created by Victor Grishchenko on 10/6/09.
6 * Copyright 2009 Delft Technical University. All rights reserved.
13 File::File (int _fd) : fd(_fd), status_(DONE), hashes(_fd)
15 bin::vec peaks = bin::peaks(hashes.data_size());
16 history.insert(history.end(),peaks.begin(),peaks.end());
17 for(bin::vec::iterator i=peaks.begin(); i!=peaks.end(); i++)
21 File::File (Sha1Hash hash, int _fd) : hashes(hash), fd(_fd), status_(EMPTY) {
26 if (fd>0) ::close(fd);
30 bool File::OfferHash (bin pos, const Sha1Hash& hash) {
31 HashTree::hashres_t res = hashes.offer(pos,hash);
32 if (res==HashTree::PEAK_ACCEPT) { // file size is finally known
33 ftruncate(fd, size());
34 LOG(INFO)<<fd<<" file size is set to "<<size();
36 status_ = IN_PROGRESS;
38 return res==HashTree::PEAK_ACCEPT || res==HashTree::ACCEPT;
42 File* File::find (const Sha1Hash& hash) {
43 for(vector<File*>::iterator i=files.begin(); i!=files.end(); i++)
44 if (*i && (*i)->hashes.root==hash)
50 int p2tp::Open (const char* filename) {
51 int fd = ::open(filename,O_RDONLY);
54 if (File::files.size()<fd+1)
55 File::files.resize(fd+1);
56 File::files[fd] = new File(fd);
60 int p2tp::Open (const Sha1Hash& root_hash, const char* filename) {
61 int fd = ::open(filename,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
64 if (File::files.size()<fd+1)
65 File::files.resize(fd+1);
66 File::files[fd] = new File(root_hash,fd);
70 size_t p2tp::file_size (int fd) { return File::file(fd)->size(); }
72 void p2tp::Close (int fid) {
73 if (!File::files[fid])
75 delete File::files[fid];
76 File::files[fid] = NULL;
80 Sha1Hash HashTree::deriveRoot () {
82 bin64_t p = peaks[i].first;
83 Sha1Hash hash = peak_hashes[i].second;
85 while (p<bin64_t::ALL) {
88 hash = Sha1Hash(hash,Sha1Hash::ZERO);
90 if (i<0 || peaks[i].first!=p.sibling())
91 return Sha1Hash::ZERO;
92 hash = Sha1Hash(peak_hashes[i].second,hash);
100 /** Three stages: have file, have root hash, have peaks. */
101 HashTree::HashTree (int _datafd, int _hashfd, Sha1Hash _root)
102 : datafd(_datafd), hashfd(_hashfd), root(_root)
104 if (root==Sha1Hash::ZERO) { // fresh file; derive the root hash
106 if (fstat(fd, &st)!=0)
109 lseek(datafd,0,SEEK_SET);
110 for(bin64_t k=0; k!=toppeak.right(); k=k.dfs_next()) {
113 int rd = read(datafd,data,1024);
116 hashes[k] = Sha1Hash(data,rd);
118 hashes[k] = Sha1Hash(hashes[k.left()],hashes[k.right()]);
121 root = hashes[toppeak];
122 for(bin64_t p=toppeak; p!=bin64_t::ALL; p=p.parent())
123 root = Sha1Hash(root,Sha1Hash::ZERO);
125 // TODO: THIS MUST BE THE "Transfer"/"File" CLASS
126 if (file_size==0) { // hash only, no file, no peak hashes
127 if (root==Sha1Hash::ZERO)
129 resize(0); // anyway, 1cell for the root, 63 for peaks
134 bool FileTransfer::acceptData (uint64_t bin, uint8_t* data, size_t len) {
138 HashTree::~HashTree () {
142 HashTree::hashres_t HashTree::offerPeak (bin pos, Sha1Hash hash) {
143 if (bin(pos+1).layer())
147 peaks.push_back(binhash(pos,hash));
148 if (deriveRoot()==root) { // bingo
149 mass = peaks.back().first;
150 length = mass.length();
151 status.resize(mass+1);
153 for(int i=0; i<peaks.size(); i++) {
154 bits[peaks[i].first] = peaks[i].second;
155 status[peaks[i].first] = true;
159 return pos.layer() ? DUNNO : REJECT;
162 HashTree::hashres_t HashTree::offer (bin pos, const Sha1Hash& hash) {
163 if (!length) // only peak hashes are accepted at this point
164 return offerPeak(pos,hash);
168 return bits[pos]==hash ? ACCEPT : REJECT;
170 // walk to the nearest proven hash
171 if (bits[pos.sibling()]==Sha1Hash::ZERO)
173 bin p = pos.parent();
175 bits[p] = Sha1Hash(bits[p.left()],bits[p.right()]);
178 if ( bits[p] == Sha1Hash(bits[p.left()],bits[p.right()]) ) {
179 for(bin i=pos; i<p; i=i.parent())
180 status[i] = status[i.sibling()] = true;