1 /**
2 * @file utils.cpp
3 * @brief Mega SDK various utilities and helper classes
4 *
5 * (c) 2013-2014 by Mega Limited, Auckland, New Zealand
6 *
7 * This file is part of the MEGA SDK - Client Access Engine.
8 *
9 * Applications using the MEGA API must present a valid application key
10 * and comply with the the rules set forth in the Terms of Service.
11 *
12 * The MEGA SDK is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * @copyright Simplified (2-clause) BSD License.
17 *
18 * You should have received a copy of the license along with this
19 * program.
20 */
21
22 #include "mega/utils.h"
23 #include "mega/logging.h"
24 #include "mega/megaclient.h"
25 #include "mega/base64.h"
26 #include "mega/serialize64.h"
27 #include "mega/filesystem.h"
28
29 #include <iomanip>
30
31 #if defined(_WIN32) && defined(_MSC_VER)
32 #include <sys/timeb.h>
33 #endif
34
35 #ifdef __APPLE__
36 #include <sys/sysctl.h>
37 #endif
38
39 namespace mega {
40
toNodeHandle(handle nodeHandle)41 string toNodeHandle(handle nodeHandle)
42 {
43 char base64Handle[12];
44 Base64::btoa((byte*)&(nodeHandle), MegaClient::NODEHANDLE, base64Handle);
45 return string(base64Handle);
46 }
47
toHandle(handle h)48 string toHandle(handle h)
49 {
50 char base64Handle[14];
51 Base64::btoa((byte*)&(h), sizeof h, base64Handle);
52 return string(base64Handle);
53 }
54
CacheableWriter(string & d)55 CacheableWriter::CacheableWriter(string& d)
56 : dest(d)
57 {
58 }
59
serializebinary(byte * data,size_t len)60 void CacheableWriter::serializebinary(byte* data, size_t len)
61 {
62 dest.append((char*)data, len);
63 }
64
serializechunkmacs(const chunkmac_map & m)65 void CacheableWriter::serializechunkmacs(const chunkmac_map& m)
66 {
67 m.serialize(dest);
68 }
69
serializecstr(const char * field,bool storeNull)70 void CacheableWriter::serializecstr(const char* field, bool storeNull)
71 {
72 unsigned short ll = (unsigned short)(field ? strlen(field) + (storeNull ? 1 : 0) : 0);
73 dest.append((char*)&ll, sizeof(ll));
74 dest.append(field, ll);
75 }
76
serializepstr(const string * field)77 void CacheableWriter::serializepstr(const string* field)
78 {
79 unsigned short ll = (unsigned short)(field ? field->size() : 0);
80 dest.append((char*)&ll, sizeof(ll));
81 if (field) dest.append(field->data(), ll);
82 }
83
serializestring(const string & field)84 void CacheableWriter::serializestring(const string& field)
85 {
86 unsigned short ll = (unsigned short)field.size();
87 dest.append((char*)&ll, sizeof(ll));
88 dest.append(field.data(), ll);
89 }
90
serializecompressed64(int64_t field)91 void CacheableWriter::serializecompressed64(int64_t field)
92 {
93 byte buf[sizeof field+1];
94 dest.append((const char*)buf, Serialize64::serialize(buf, field));
95 }
96
serializei64(int64_t field)97 void CacheableWriter::serializei64(int64_t field)
98 {
99 dest.append((char*)&field, sizeof(field));
100 }
101
serializeu32(uint32_t field)102 void CacheableWriter::serializeu32(uint32_t field)
103 {
104 dest.append((char*)&field, sizeof(field));
105 }
106
serializehandle(handle field)107 void CacheableWriter::serializehandle(handle field)
108 {
109 dest.append((char*)&field, sizeof(field));
110 }
111
serializenodehandle(handle field)112 void CacheableWriter::serializenodehandle(handle field)
113 {
114 dest.append((const char*)&field, MegaClient::NODEHANDLE);
115 }
116
serializefsfp(fsfp_t field)117 void CacheableWriter::serializefsfp(fsfp_t field)
118 {
119 dest.append((char*)&field, sizeof(field));
120 }
121
serializebool(bool field)122 void CacheableWriter::serializebool(bool field)
123 {
124 dest.append((char*)&field, sizeof(field));
125 }
126
serializebyte(byte field)127 void CacheableWriter::serializebyte(byte field)
128 {
129 dest.append((char*)&field, sizeof(field));
130 }
131
serializedouble(double field)132 void CacheableWriter::serializedouble(double field)
133 {
134 dest.append((char*)&field, sizeof(field));
135 }
136
serializeexpansionflags(bool b0,bool b1,bool b2,bool b3,bool b4,bool b5,bool b6,bool b7)137 void CacheableWriter::serializeexpansionflags(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7)
138 {
139 unsigned char b[8];
140 b[0] = b0;
141 b[1] = b1;
142 b[2] = b2;
143 b[3] = b3;
144 b[4] = b4;
145 b[5] = b5;
146 b[6] = b6;
147 b[7] = b7;
148 dest.append((char*)b, 8);
149 }
150
151
CacheableReader(const string & d)152 CacheableReader::CacheableReader(const string& d)
153 : ptr(d.data())
154 , end(ptr + d.size())
155 , fieldnum(0)
156 {
157 }
158
eraseused(string & d)159 void CacheableReader::eraseused(string& d)
160 {
161 assert(end == d.data() + d.size());
162 d.erase(0, ptr - d.data());
163 }
164
unserializecstr(string & s,bool removeNull)165 bool CacheableReader::unserializecstr(string& s, bool removeNull)
166 {
167 if (ptr + sizeof(unsigned short) > end)
168 {
169 return false;
170 }
171
172 unsigned short len = MemAccess::get<unsigned short>(ptr);
173 ptr += sizeof(len);
174
175 if (ptr + len > end)
176 {
177 return false;
178 }
179
180 if (len)
181 {
182 s.assign(ptr, len - (removeNull ? 1 : 0));
183 }
184 ptr += len;
185 fieldnum += 1;
186 return true;
187 }
188
189
unserializestring(string & s)190 bool CacheableReader::unserializestring(string& s)
191 {
192 if (ptr + sizeof(unsigned short) > end)
193 {
194 return false;
195 }
196
197 unsigned short len = MemAccess::get<unsigned short>(ptr);
198 ptr += sizeof(len);
199
200 if (ptr + len > end)
201 {
202 return false;
203 }
204
205 if (len)
206 {
207 s.assign(ptr, len);
208 }
209 ptr += len;
210 fieldnum += 1;
211 return true;
212 }
213
unserializebinary(byte * data,size_t len)214 bool CacheableReader::unserializebinary(byte* data, size_t len)
215 {
216 if (ptr + len > end)
217 {
218 return false;
219 }
220
221 memcpy(data, ptr, len);
222 ptr += len;
223 fieldnum += 1;
224 return true;
225 }
226
227
serialize(string & d) const228 void chunkmac_map::serialize(string& d) const
229 {
230 unsigned short ll = (unsigned short)size();
231 d.append((char*)&ll, sizeof(ll));
232 for (const_iterator it = begin(); it != end(); it++)
233 {
234 d.append((char*)&it->first, sizeof(it->first));
235 d.append((char*)&it->second, sizeof(it->second));
236 }
237 }
238
unserialize(const char * & ptr,const char * end)239 bool chunkmac_map::unserialize(const char*& ptr, const char* end)
240 {
241 unsigned short ll;
242 if ((ptr + sizeof(ll) > end) || ptr + (ll = MemAccess::get<unsigned short>(ptr)) * (sizeof(m_off_t) + sizeof(ChunkMAC)) + sizeof(ll) > end)
243 {
244 return false;
245 }
246
247 ptr += sizeof(ll);
248
249 for (int i = 0; i < ll; i++)
250 {
251 m_off_t pos = MemAccess::get<m_off_t>(ptr);
252 ptr += sizeof(m_off_t);
253
254 memcpy(&((*this)[pos]), ptr, sizeof(ChunkMAC));
255 ptr += sizeof(ChunkMAC);
256 }
257 return true;
258 }
259
calcprogress(m_off_t size,m_off_t & chunkpos,m_off_t & progresscompleted,m_off_t * lastblockprogress)260 void chunkmac_map::calcprogress(m_off_t size, m_off_t& chunkpos, m_off_t& progresscompleted, m_off_t* lastblockprogress)
261 {
262 chunkpos = 0;
263 progresscompleted = 0;
264
265 for (chunkmac_map::iterator it = begin(); it != end(); ++it)
266 {
267 m_off_t chunkceil = ChunkedHash::chunkceil(it->first, size);
268
269 if (chunkpos == it->first && it->second.finished)
270 {
271 chunkpos = chunkceil;
272 progresscompleted = chunkceil;
273 }
274 else if (it->second.finished)
275 {
276 m_off_t chunksize = chunkceil - ChunkedHash::chunkfloor(it->first);
277 progresscompleted += chunksize;
278 }
279 else
280 {
281 progresscompleted += it->second.offset;
282 if (lastblockprogress)
283 {
284 *lastblockprogress += it->second.offset;
285 }
286 }
287 }
288 }
289
nextUnprocessedPosFrom(m_off_t pos)290 m_off_t chunkmac_map::nextUnprocessedPosFrom(m_off_t pos)
291 {
292 for (const_iterator it = find(ChunkedHash::chunkfloor(pos));
293 it != end();
294 it = find(ChunkedHash::chunkfloor(pos)))
295 {
296 if (it->second.finished)
297 {
298 pos = ChunkedHash::chunkceil(pos);
299 }
300 else
301 {
302 pos += it->second.offset;
303 break;
304 }
305 }
306 return pos;
307 }
308
expandUnprocessedPiece(m_off_t pos,m_off_t npos,m_off_t fileSize,m_off_t maxReqSize)309 m_off_t chunkmac_map::expandUnprocessedPiece(m_off_t pos, m_off_t npos, m_off_t fileSize, m_off_t maxReqSize)
310 {
311 for (iterator it = find(npos);
312 npos < fileSize && (npos - pos) <= maxReqSize && (it == end() || (!it->second.finished && !it->second.offset));
313 it = find(npos))
314 {
315 npos = ChunkedHash::chunkceil(npos, fileSize);
316 }
317 return npos;
318 }
319
finishedUploadChunks(chunkmac_map & macs)320 void chunkmac_map::finishedUploadChunks(chunkmac_map& macs)
321 {
322 for (auto& m : macs)
323 {
324 m.second.finished = true;
325 (*this)[m.first] = m.second;
326 LOG_verbose << "Upload chunk completed: " << m.first;
327 }
328 }
329
330 // coalesce block macs into file mac
macsmac(SymmCipher * cipher)331 int64_t chunkmac_map::macsmac(SymmCipher *cipher)
332 {
333 byte mac[SymmCipher::BLOCKSIZE] = { 0 };
334
335 for (chunkmac_map::iterator it = begin(); it != end(); it++)
336 {
337 assert(it->first == ChunkedHash::chunkfloor(it->first));
338 // LOG_debug << "macsmac input: " << it->first << ": " << Base64Str<sizeof it->second.mac>(it->second.mac);
339 SymmCipher::xorblock(it->second.mac, mac);
340 cipher->ecb_encrypt(mac);
341 }
342
343 uint32_t* m = (uint32_t*)mac;
344
345 m[0] ^= m[1];
346 m[1] = m[2] ^ m[3];
347
348 return MemAccess::get<int64_t>((const char*)mac);
349 }
350
unserializechunkmacs(chunkmac_map & m)351 bool CacheableReader::unserializechunkmacs(chunkmac_map& m)
352 {
353 if (m.unserialize(ptr, end)) // ptr is adjusted by reference
354 {
355 fieldnum += 1;
356 return true;
357 }
358 return false;
359 }
360
unserializecompressed64(uint64_t & field)361 bool CacheableReader::unserializecompressed64(uint64_t& field)
362 {
363 int fieldSize;
364 if ((fieldSize = Serialize64::unserialize((byte*)ptr, static_cast<int>(end - ptr), &field)) < 0)
365 {
366 LOG_err << "Serialize64 unserialization failed - malformed field";
367 return false;
368 }
369 else
370 {
371 ptr += fieldSize;
372 }
373 return true;
374 }
375
unserializei64(int64_t & field)376 bool CacheableReader::unserializei64(int64_t& field)
377 {
378 if (ptr + sizeof(int64_t) > end)
379 {
380 return false;
381 }
382 field = MemAccess::get<int64_t>(ptr);
383 ptr += sizeof(int64_t);
384 fieldnum += 1;
385 return true;
386 }
387
unserializeu32(uint32_t & field)388 bool CacheableReader::unserializeu32(uint32_t& field)
389 {
390 if (ptr + sizeof(uint32_t) > end)
391 {
392 return false;
393 }
394 field = MemAccess::get<uint32_t>(ptr);
395 ptr += sizeof(uint32_t);
396 fieldnum += 1;
397 return true;
398 }
399
unserializehandle(handle & field)400 bool CacheableReader::unserializehandle(handle& field)
401 {
402 if (ptr + sizeof(handle) > end)
403 {
404 return false;
405 }
406 field = MemAccess::get<handle>(ptr);
407 ptr += sizeof(handle);
408 fieldnum += 1;
409 return true;
410 }
411
unserializenodehandle(handle & field)412 bool CacheableReader::unserializenodehandle(handle& field)
413 {
414 if (ptr + MegaClient::NODEHANDLE > end)
415 {
416 return false;
417 }
418 field = 0;
419 memcpy((char*)&field, ptr, MegaClient::NODEHANDLE);
420 ptr += MegaClient::NODEHANDLE;
421 fieldnum += 1;
422 return true;
423 }
424
unserializefsfp(fsfp_t & field)425 bool CacheableReader::unserializefsfp(fsfp_t& field)
426 {
427 if (ptr + sizeof(fsfp_t) > end)
428 {
429 return false;
430 }
431 field = MemAccess::get<fsfp_t>(ptr);
432 ptr += sizeof(fsfp_t);
433 fieldnum += 1;
434 return true;
435 }
436
unserializebool(bool & field)437 bool CacheableReader::unserializebool(bool& field)
438 {
439 if (ptr + sizeof(bool) > end)
440 {
441 return false;
442 }
443 field = MemAccess::get<bool>(ptr);
444 ptr += sizeof(bool);
445 fieldnum += 1;
446 return true;
447 }
448
unserializebyte(byte & field)449 bool CacheableReader::unserializebyte(byte& field)
450 {
451 if (ptr + sizeof(byte) > end)
452 {
453 return false;
454 }
455 field = MemAccess::get<byte>(ptr);
456 ptr += sizeof(byte);
457 fieldnum += 1;
458 return true;
459 }
460
unserializedouble(double & field)461 bool CacheableReader::unserializedouble(double& field)
462 {
463 if (ptr + sizeof(double) > end)
464 {
465 return false;
466 }
467 field = MemAccess::get<double>(ptr);
468 ptr += sizeof(double);
469 fieldnum += 1;
470 return true;
471 }
472
unserializeexpansionflags(unsigned char field[8],unsigned usedFlagCount)473 bool CacheableReader::unserializeexpansionflags(unsigned char field[8], unsigned usedFlagCount)
474 {
475 if (ptr + 8 > end)
476 {
477 return false;
478 }
479 memcpy(field, ptr, 8);
480
481 for (int i = usedFlagCount; i < 8; i++ )
482 {
483 if (field[i])
484 {
485 LOG_err << "Unserialization failed in expansion flags, invalid version detected. Fieldnum: " << fieldnum;
486 return false;
487 }
488 }
489
490 ptr += 8;
491 fieldnum += 1;
492 return true;
493 }
494
495 #ifdef ENABLE_CHAT
TextChat()496 TextChat::TextChat()
497 {
498 id = UNDEF;
499 priv = PRIV_UNKNOWN;
500 shard = -1;
501 userpriv = NULL;
502 group = false;
503 ou = UNDEF;
504 resetTag();
505 ts = 0;
506 flags = 0;
507 publicchat = false;
508
509 memset(&changed, 0, sizeof(changed));
510 }
511
~TextChat()512 TextChat::~TextChat()
513 {
514 delete userpriv;
515 }
516
serialize(string * d)517 bool TextChat::serialize(string *d)
518 {
519 unsigned short ll;
520
521 d->append((char*)&id, sizeof id);
522 d->append((char*)&priv, sizeof priv);
523 d->append((char*)&shard, sizeof shard);
524
525 ll = (unsigned short)(userpriv ? userpriv->size() : 0);
526 d->append((char*)&ll, sizeof ll);
527 if (userpriv)
528 {
529 userpriv_vector::iterator it = userpriv->begin();
530 while (it != userpriv->end())
531 {
532 handle uh = it->first;
533 d->append((char*)&uh, sizeof uh);
534
535 privilege_t priv = it->second;
536 d->append((char*)&priv, sizeof priv);
537
538 it++;
539 }
540 }
541
542 d->append((char*)&group, sizeof group);
543
544 // title is a binary array
545 ll = (unsigned short)title.size();
546 d->append((char*)&ll, sizeof ll);
547 d->append(title.data(), ll);
548
549 d->append((char*)&ou, sizeof ou);
550 d->append((char*)&ts, sizeof(ts));
551
552 char hasAttachments = attachedNodes.size() != 0;
553 d->append((char*)&hasAttachments, 1);
554
555 d->append((char*)&flags, 1);
556
557 char mode = publicchat ? 1 : 0;
558 d->append((char*)&mode, 1);
559
560 char hasUnifiedKey = unifiedKey.size() ? 1 : 0;
561 d->append((char *)&hasUnifiedKey, 1);
562
563 d->append("\0\0\0\0\0\0", 6); // additional bytes for backwards compatibility
564
565 if (hasAttachments)
566 {
567 ll = (unsigned short)attachedNodes.size(); // number of nodes with granted access
568 d->append((char*)&ll, sizeof ll);
569
570 for (attachments_map::iterator it = attachedNodes.begin(); it != attachedNodes.end(); it++)
571 {
572 d->append((char*)&it->first, sizeof it->first); // nodehandle
573
574 ll = (unsigned short)it->second.size(); // number of users with granted access to the node
575 d->append((char*)&ll, sizeof ll);
576 for (set<handle>::iterator ituh = it->second.begin(); ituh != it->second.end(); ituh++)
577 {
578 d->append((char*)&(*ituh), sizeof *ituh); // userhandle
579 }
580 }
581 }
582
583 if (hasUnifiedKey)
584 {
585 ll = (unsigned short) unifiedKey.size();
586 d->append((char *)&ll, sizeof ll);
587 d->append((char*) unifiedKey.data(), unifiedKey.size());
588 }
589
590 return true;
591 }
592
unserialize(class MegaClient * client,string * d)593 TextChat* TextChat::unserialize(class MegaClient *client, string *d)
594 {
595 handle id;
596 privilege_t priv;
597 int shard;
598 userpriv_vector *userpriv = NULL;
599 bool group;
600 string title; // byte array
601 handle ou;
602 m_time_t ts;
603 byte flags;
604 char hasAttachments;
605 attachments_map attachedNodes;
606 bool publicchat;
607 string unifiedKey;
608
609 unsigned short ll;
610 const char* ptr = d->data();
611 const char* end = ptr + d->size();
612
613 if (ptr + sizeof(handle) + sizeof(privilege_t) + sizeof(int) + sizeof(short) > end)
614 {
615 return NULL;
616 }
617
618 id = MemAccess::get<handle>(ptr);
619 ptr += sizeof id;
620
621 priv = MemAccess::get<privilege_t>(ptr);
622 ptr += sizeof priv;
623
624 shard = MemAccess::get<int>(ptr);
625 ptr += sizeof shard;
626
627 ll = MemAccess::get<unsigned short>(ptr);
628 ptr += sizeof ll;
629 if (ll)
630 {
631 if (ptr + ll * (sizeof(handle) + sizeof(privilege_t)) > end)
632 {
633 return NULL;
634 }
635
636 userpriv = new userpriv_vector();
637
638 for (unsigned short i = 0; i < ll; i++)
639 {
640 handle uh = MemAccess::get<handle>(ptr);
641 ptr += sizeof uh;
642
643 privilege_t priv = MemAccess::get<privilege_t>(ptr);
644 ptr += sizeof priv;
645
646 userpriv->push_back(userpriv_pair(uh, priv));
647 }
648
649 if (priv == PRIV_RM) // clear peerlist if removed
650 {
651 delete userpriv;
652 userpriv = NULL;
653 }
654 }
655
656 if (ptr + sizeof(bool) + sizeof(unsigned short) > end)
657 {
658 delete userpriv;
659 return NULL;
660 }
661
662 group = MemAccess::get<bool>(ptr);
663 ptr += sizeof group;
664
665 ll = MemAccess::get<unsigned short>(ptr);
666 ptr += sizeof ll;
667 if (ll)
668 {
669 if (ptr + ll > end)
670 {
671 delete userpriv;
672 return NULL;
673 }
674 title.assign(ptr, ll);
675 }
676 ptr += ll;
677
678 if (ptr + sizeof(handle) + sizeof(m_time_t) + sizeof(char) + 9 > end)
679 {
680 delete userpriv;
681 return NULL;
682 }
683
684 ou = MemAccess::get<handle>(ptr);
685 ptr += sizeof ou;
686
687 ts = MemAccess::get<m_time_t>(ptr);
688 ptr += sizeof(m_time_t);
689
690 hasAttachments = MemAccess::get<char>(ptr);
691 ptr += sizeof hasAttachments;
692
693 flags = MemAccess::get<char>(ptr);
694 ptr += sizeof(char);
695
696 char mode = MemAccess::get<char>(ptr);
697 publicchat = (mode == 1);
698 ptr += sizeof(char);
699
700 char hasUnifiedKey = MemAccess::get<char>(ptr);
701 ptr += sizeof(char);
702
703 for (int i = 6; i--;)
704 {
705 if (ptr + MemAccess::get<unsigned char>(ptr) < end)
706 {
707 ptr += MemAccess::get<unsigned char>(ptr) + 1;
708 }
709 }
710
711 if (hasAttachments)
712 {
713 unsigned short numNodes = 0;
714 if (ptr + sizeof numNodes > end)
715 {
716 delete userpriv;
717 return NULL;
718 }
719
720 numNodes = MemAccess::get<unsigned short>(ptr);
721 ptr += sizeof numNodes;
722
723 for (int i = 0; i < numNodes; i++)
724 {
725 handle h = UNDEF;
726 unsigned short numUsers = 0;
727 if (ptr + sizeof h + sizeof numUsers > end)
728 {
729 delete userpriv;
730 return NULL;
731 }
732
733 h = MemAccess::get<handle>(ptr);
734 ptr += sizeof h;
735
736 numUsers = MemAccess::get<unsigned short>(ptr);
737 ptr += sizeof numUsers;
738
739 handle uh = UNDEF;
740 if (ptr + (numUsers * sizeof(uh)) > end)
741 {
742 delete userpriv;
743 return NULL;
744 }
745
746 for (int j = 0; j < numUsers; j++)
747 {
748 uh = MemAccess::get<handle>(ptr);
749 ptr += sizeof uh;
750
751 attachedNodes[h].insert(uh);
752 }
753 }
754 }
755
756 if (hasUnifiedKey)
757 {
758 unsigned short keylen = 0;
759 if (ptr + sizeof keylen > end)
760 {
761 delete userpriv;
762 return NULL;
763 }
764
765 keylen = MemAccess::get<unsigned short>(ptr);
766 ptr += sizeof keylen;
767
768 if (ptr + keylen > end)
769 {
770 delete userpriv;
771 return NULL;
772 }
773
774 unifiedKey.assign(ptr, keylen);
775 ptr += keylen;
776 }
777
778 if (ptr < end)
779 {
780 delete userpriv;
781 return NULL;
782 }
783
784 if (client->chats.find(id) == client->chats.end())
785 {
786 client->chats[id] = new TextChat();
787 }
788 else
789 {
790 LOG_warn << "Unserialized a chat already in RAM";
791 }
792 TextChat* chat = client->chats[id];
793 chat->id = id;
794 chat->priv = priv;
795 chat->shard = shard;
796 chat->userpriv = userpriv;
797 chat->group = group;
798 chat->title = title;
799 chat->ou = ou;
800 chat->resetTag();
801 chat->ts = ts;
802 chat->flags = flags;
803 chat->attachedNodes = attachedNodes;
804 chat->publicchat = publicchat;
805 chat->unifiedKey = unifiedKey;
806
807 memset(&chat->changed, 0, sizeof(chat->changed));
808
809 return chat;
810 }
811
setTag(int tag)812 void TextChat::setTag(int tag)
813 {
814 if (this->tag != 0) // external changes prevail
815 {
816 this->tag = tag;
817 }
818 }
819
getTag()820 int TextChat::getTag()
821 {
822 return tag;
823 }
824
resetTag()825 void TextChat::resetTag()
826 {
827 tag = -1;
828 }
829
setNodeUserAccess(handle h,handle uh,bool revoke)830 bool TextChat::setNodeUserAccess(handle h, handle uh, bool revoke)
831 {
832 if (revoke)
833 {
834 attachments_map::iterator uhit = attachedNodes.find(h);
835 if (uhit != attachedNodes.end())
836 {
837 uhit->second.erase(uh);
838 if (uhit->second.empty())
839 {
840 attachedNodes.erase(h);
841 changed.attachments = true;
842 }
843 return true;
844 }
845 }
846 else
847 {
848 attachedNodes[h].insert(uh);
849 changed.attachments = true;
850 return true;
851 }
852
853 return false;
854 }
855
setFlags(byte newFlags)856 bool TextChat::setFlags(byte newFlags)
857 {
858 if (flags == newFlags)
859 {
860 return false;
861 }
862
863 flags = newFlags;
864 changed.flags = true;
865
866 return true;
867 }
868
isFlagSet(uint8_t offset) const869 bool TextChat::isFlagSet(uint8_t offset) const
870 {
871 return (flags >> offset) & 1U;
872 }
873
setMode(bool publicchat)874 bool TextChat::setMode(bool publicchat)
875 {
876 if (this->publicchat == publicchat)
877 {
878 return false;
879 }
880
881 this->publicchat = publicchat;
882 changed.mode = true;
883
884 return true;
885 }
886
setFlag(bool value,uint8_t offset)887 bool TextChat::setFlag(bool value, uint8_t offset)
888 {
889 if (bool((flags >> offset) & 1U) == value)
890 {
891 return false;
892 }
893
894 flags ^= (1U << offset);
895 changed.flags = true;
896
897 return true;
898 }
899 #endif
900
901 /**
902 * @brief Encrypts a string after padding it to block length.
903 *
904 * Note: With an IV, only use the first 8 bytes.
905 *
906 * @param data Data buffer to be encrypted. Encryption is done in-place,
907 * so cipher text will be in `data` afterwards as well.
908 * @param key AES key for encryption.
909 * @param iv Optional initialisation vector for encryption. Will use a
910 * zero IV if not given. If `iv` is a zero length string, a new IV
911 * for encryption will be generated and available through the reference.
912 * @return Void.
913 */
encrypt(PrnGen & rng,string * data,SymmCipher * key,string * iv)914 void PaddedCBC::encrypt(PrnGen &rng, string* data, SymmCipher* key, string* iv)
915 {
916 if (iv)
917 {
918 // Make a new 8-byte IV, if the one passed is zero length.
919 if (iv->size() == 0)
920 {
921 byte* buf = new byte[8];
922 rng.genblock(buf, 8);
923 iv->append((char*)buf);
924 delete [] buf;
925 }
926
927 // Truncate a longer IV to its first 8 bytes.
928 if (iv->size() > 8)
929 {
930 iv->resize(8);
931 }
932
933 // Bring up the IV size to BLOCKSIZE.
934 iv->resize(key->BLOCKSIZE);
935 }
936
937 // Pad to block size and encrypt.
938 data->append("E");
939 data->resize((data->size() + key->BLOCKSIZE - 1) & - key->BLOCKSIZE, 'P');
940 if (iv)
941 {
942 key->cbc_encrypt((byte*)data->data(), data->size(),
943 (const byte*)iv->data());
944 }
945 else
946 {
947 key->cbc_encrypt((byte*)data->data(), data->size());
948 }
949
950 // Truncate IV back to the first 8 bytes only..
951 if (iv)
952 {
953 iv->resize(8);
954 }
955 }
956
957 /**
958 * @brief Decrypts a string and strips the padding.
959 *
960 * Note: With an IV, only use the first 8 bytes.
961 *
962 * @param data Data buffer to be decrypted. Decryption is done in-place,
963 * so plain text will be in `data` afterwards as well.
964 * @param key AES key for decryption.
965 * @param iv Optional initialisation vector for encryption. Will use a
966 * zero IV if not given.
967 * @return Void.
968 */
decrypt(string * data,SymmCipher * key,string * iv)969 bool PaddedCBC::decrypt(string* data, SymmCipher* key, string* iv)
970 {
971 if (iv)
972 {
973 // Truncate a longer IV to its first 8 bytes.
974 if (iv->size() > 8)
975 {
976 iv->resize(8);
977 }
978
979 // Bring up the IV size to BLOCKSIZE.
980 iv->resize(key->BLOCKSIZE);
981 }
982
983 if ((data->size() & (key->BLOCKSIZE - 1)))
984 {
985 return false;
986 }
987
988 // Decrypt and unpad.
989 if (iv)
990 {
991 key->cbc_decrypt((byte*)data->data(), data->size(),
992 (const byte*)iv->data());
993 }
994 else
995 {
996 key->cbc_decrypt((byte*)data->data(), data->size());
997 }
998
999 size_t p = data->find_last_of('E');
1000
1001 if (p == string::npos)
1002 {
1003 return false;
1004 }
1005
1006 data->resize(p);
1007
1008 return true;
1009 }
1010
1011 // start of chunk
chunkfloor(m_off_t p)1012 m_off_t ChunkedHash::chunkfloor(m_off_t p)
1013 {
1014 m_off_t cp, np;
1015
1016 cp = 0;
1017
1018 for (unsigned i = 1; i <= 8; i++)
1019 {
1020 np = cp + i * SEGSIZE;
1021
1022 if ((p >= cp) && (p < np))
1023 {
1024 return cp;
1025 }
1026
1027 cp = np;
1028 }
1029
1030 return ((p - cp) & - (8 * SEGSIZE)) + cp;
1031 }
1032
1033 // end of chunk (== start of next chunk)
chunkceil(m_off_t p,m_off_t limit)1034 m_off_t ChunkedHash::chunkceil(m_off_t p, m_off_t limit)
1035 {
1036 m_off_t cp, np;
1037
1038 cp = 0;
1039
1040 for (unsigned i = 1; i <= 8; i++)
1041 {
1042 np = cp + i * SEGSIZE;
1043
1044 if ((p >= cp) && (p < np))
1045 {
1046 return (limit < 0 || np < limit) ? np : limit;
1047 }
1048
1049 cp = np;
1050 }
1051
1052 np = ((p - cp) & - (8 * SEGSIZE)) + cp + 8 * SEGSIZE;
1053 return (limit < 0 || np < limit) ? np : limit;
1054 }
1055
1056
1057 // cryptographic signature generation/verification
HashSignature(Hash * h)1058 HashSignature::HashSignature(Hash* h)
1059 {
1060 hash = h;
1061 }
1062
~HashSignature()1063 HashSignature::~HashSignature()
1064 {
1065 delete hash;
1066 }
1067
add(const byte * data,unsigned len)1068 void HashSignature::add(const byte* data, unsigned len)
1069 {
1070 hash->add(data, len);
1071 }
1072
get(AsymmCipher * privk,byte * sigbuf,unsigned sigbuflen)1073 unsigned HashSignature::get(AsymmCipher* privk, byte* sigbuf, unsigned sigbuflen)
1074 {
1075 string h;
1076
1077 hash->get(&h);
1078
1079 return privk->rawdecrypt((const byte*)h.data(), h.size(), sigbuf, sigbuflen);
1080 }
1081
checksignature(AsymmCipher * pubk,const byte * sig,unsigned len)1082 bool HashSignature::checksignature(AsymmCipher* pubk, const byte* sig, unsigned len)
1083 {
1084 string h, s;
1085 unsigned size;
1086
1087 hash->get(&h);
1088
1089 s.resize(h.size());
1090
1091 if (!(size = pubk->rawencrypt(sig, len, (byte*)s.data(), s.size())))
1092 {
1093 return 0;
1094 }
1095
1096 if (size < h.size())
1097 {
1098 // left-pad with 0
1099 s.insert(0, h.size() - size, 0);
1100 s.resize(h.size());
1101 }
1102
1103 return s == h;
1104 }
1105
PayCrypter(PrnGen & rng)1106 PayCrypter::PayCrypter(PrnGen &rng)
1107 : rng(rng)
1108 {
1109 rng.genblock(keys, ENC_KEY_BYTES + MAC_KEY_BYTES);
1110 encKey = keys;
1111 hmacKey = keys+ENC_KEY_BYTES;
1112
1113 rng.genblock(iv, IV_BYTES);
1114 }
1115
setKeys(const byte * newEncKey,const byte * newHmacKey,const byte * newIv)1116 void PayCrypter::setKeys(const byte *newEncKey, const byte *newHmacKey, const byte *newIv)
1117 {
1118 memcpy(encKey, newEncKey, ENC_KEY_BYTES);
1119 memcpy(hmacKey, newHmacKey, MAC_KEY_BYTES);
1120 memcpy(iv, newIv, IV_BYTES);
1121 }
1122
encryptPayload(const string * cleartext,string * result)1123 bool PayCrypter::encryptPayload(const string *cleartext, string *result)
1124 {
1125 //Check parameters
1126 if(!cleartext || !result)
1127 {
1128 return false;
1129 }
1130
1131 //AES-CBC encryption
1132 string encResult;
1133 SymmCipher sym(encKey);
1134 sym.cbc_encrypt_pkcs_padding(cleartext, iv, &encResult);
1135
1136 //Prepare the message to authenticate (IV + cipher text)
1137 string toAuthenticate((char *)iv, IV_BYTES);
1138 toAuthenticate.append(encResult);
1139
1140 //HMAC-SHA256
1141 HMACSHA256 hmacProcessor(hmacKey, MAC_KEY_BYTES);
1142 hmacProcessor.add((byte *)toAuthenticate.data(), toAuthenticate.size());
1143 result->resize(32);
1144 hmacProcessor.get((byte *)result->data());
1145
1146 //Complete the result (HMAC + IV - ciphertext)
1147 result->append((char *)iv, IV_BYTES);
1148 result->append(encResult);
1149 return true;
1150 }
1151
rsaEncryptKeys(const string * cleartext,const byte * pubkdata,int pubkdatalen,string * result,bool randompadding)1152 bool PayCrypter::rsaEncryptKeys(const string *cleartext, const byte *pubkdata, int pubkdatalen, string *result, bool randompadding)
1153 {
1154 //Check parameters
1155 if(!cleartext || !pubkdata || !result)
1156 {
1157 return false;
1158 }
1159
1160 //Create an AsymmCipher with the public key
1161 AsymmCipher asym;
1162 asym.setkey(AsymmCipher::PUBKEY, pubkdata, pubkdatalen);
1163
1164 //Prepare the message to encrypt (2-byte header + clear text)
1165 string keyString;
1166 keyString.append(1, (byte)(cleartext->size() >> 8));
1167 keyString.append(1, (byte)(cleartext->size()));
1168 keyString.append(*cleartext);
1169
1170 //Save the length of the valid message
1171 size_t keylen = keyString.size();
1172
1173 //Resize to add padding
1174 keyString.resize(asym.key[AsymmCipher::PUB_PQ].ByteCount() - 2);
1175
1176 //Add padding
1177 if(randompadding)
1178 {
1179 rng.genblock((byte *)keyString.data() + keylen, keyString.size() - keylen);
1180 }
1181
1182 //RSA encryption
1183 result->resize(pubkdatalen);
1184 result->resize(asym.rawencrypt((byte *)keyString.data(), keyString.size(), (byte *)result->data(), result->size()));
1185
1186 //Complete the result (2-byte header + RSA result)
1187 size_t reslen = result->size();
1188 result->insert(0, 1, (byte)(reslen >> 8));
1189 result->insert(1, 1, (byte)(reslen));
1190 return true;
1191 }
1192
hybridEncrypt(const string * cleartext,const byte * pubkdata,int pubkdatalen,string * result,bool randompadding)1193 bool PayCrypter::hybridEncrypt(const string *cleartext, const byte *pubkdata, int pubkdatalen, string *result, bool randompadding)
1194 {
1195 if(!cleartext || !pubkdata || !result)
1196 {
1197 return false;
1198 }
1199
1200 //Generate the payload
1201 string payloadString;
1202 encryptPayload(cleartext, &payloadString);
1203
1204 //RSA encryption
1205 string rsaKeyCipher;
1206 string keysString;
1207 keysString.assign((char *)keys, ENC_KEY_BYTES + MAC_KEY_BYTES);
1208 rsaEncryptKeys(&keysString, pubkdata, pubkdatalen, &rsaKeyCipher, randompadding);
1209
1210 //Complete the result
1211 *result = rsaKeyCipher + payloadString;
1212 return true;
1213 }
1214
1215 #ifdef _WIN32
mega_snprintf(char * s,size_t n,const char * format,...)1216 int mega_snprintf(char *s, size_t n, const char *format, ...)
1217 {
1218 va_list args;
1219 int ret;
1220
1221 if (!s || n <= 0)
1222 {
1223 return -1;
1224 }
1225
1226 va_start(args, format);
1227 ret = vsnprintf(s, n, format, args);
1228 va_end(args);
1229
1230 s[n - 1] = '\0';
1231 return ret;
1232 }
1233 #endif
1234
tlvRecordsToContainer(PrnGen & rng,SymmCipher * key,encryptionsetting_t encSetting)1235 string * TLVstore::tlvRecordsToContainer(PrnGen &rng, SymmCipher *key, encryptionsetting_t encSetting)
1236 {
1237 // decide nonce/IV and auth. tag lengths based on the `mode`
1238 unsigned ivlen = TLVstore::getIvlen(encSetting);
1239 unsigned taglen = TLVstore::getTaglen(encSetting);
1240 encryptionmode_t encMode = TLVstore::getMode(encSetting);
1241
1242 if (!ivlen || !taglen || encMode == AES_MODE_UNKNOWN)
1243 {
1244 return NULL;
1245 }
1246
1247 // serialize the TLV records
1248 string *container = tlvRecordsToContainer();
1249
1250 // generate IV array
1251 byte *iv = new byte[ivlen];
1252 rng.genblock(iv, ivlen);
1253
1254 string cipherText;
1255
1256 // encrypt the bytes using the specified mode
1257
1258 if (encMode == AES_MODE_CCM) // CCM or GCM_BROKEN (same than CCM)
1259 {
1260 key->ccm_encrypt(container, iv, ivlen, taglen, &cipherText);
1261 }
1262 else if (encMode == AES_MODE_GCM) // then use GCM
1263 {
1264 key->gcm_encrypt(container, iv, ivlen, taglen, &cipherText);
1265 }
1266
1267 string *result = new string;
1268 result->resize(1);
1269 result->at(0) = static_cast<char>(encSetting);
1270 result->append((char*) iv, ivlen);
1271 result->append((char*) cipherText.data(), cipherText.length()); // includes auth. tag
1272
1273 delete [] iv;
1274 delete container;
1275
1276 return result;
1277 }
1278
tlvRecordsToContainer()1279 string* TLVstore::tlvRecordsToContainer()
1280 {
1281 string *result = new string;
1282 size_t offset = 0;
1283 size_t length;
1284
1285 for (TLV_map::iterator it = tlv.begin(); it != tlv.end(); it++)
1286 {
1287 // copy Type
1288 result->append(it->first);
1289 offset += it->first.length() + 1; // keep the NULL-char for Type string
1290
1291 // set Length of value
1292 length = it->second.length();
1293 result->resize(offset + 2);
1294 result->at(offset) = static_cast<char>(length >> 8);
1295 result->at(offset + 1) = static_cast<char>(length & 0xFF);
1296 offset += 2;
1297
1298 // copy the Value
1299 result->append((char*)it->second.data(), it->second.length());
1300 offset += it->second.length();
1301 }
1302
1303 return result;
1304 }
1305
get(string type) const1306 std::string TLVstore::get(string type) const
1307 {
1308 return tlv.at(type);
1309 }
1310
getMap() const1311 const TLV_map * TLVstore::getMap() const
1312 {
1313 return &tlv;
1314 }
1315
getKeys() const1316 vector<string> *TLVstore::getKeys() const
1317 {
1318 vector<string> *keys = new vector<string>;
1319 for (string_map::const_iterator it = tlv.begin(); it != tlv.end(); it++)
1320 {
1321 keys->push_back(it->first);
1322 }
1323 return keys;
1324 }
1325
find(string type) const1326 bool TLVstore::find(string type) const
1327 {
1328 return (tlv.find(type) != tlv.end());
1329 }
1330
set(string type,string value)1331 void TLVstore::set(string type, string value)
1332 {
1333 tlv[type] = value;
1334 }
1335
reset(std::string type)1336 void TLVstore::reset(std::string type)
1337 {
1338 tlv.erase(type);
1339 }
1340
size()1341 size_t TLVstore::size()
1342 {
1343 return tlv.size();
1344 }
1345
getTaglen(int mode)1346 unsigned TLVstore::getTaglen(int mode)
1347 {
1348
1349 switch (mode)
1350 {
1351 case AES_CCM_10_16:
1352 case AES_CCM_12_16:
1353 case AES_GCM_12_16_BROKEN:
1354 case AES_GCM_12_16:
1355 return 16;
1356
1357 case AES_CCM_10_08:
1358 case AES_GCM_10_08_BROKEN:
1359 case AES_GCM_10_08:
1360 return 8;
1361
1362 default: // unknown block encryption mode
1363 return 0;
1364 }
1365 }
1366
getIvlen(int mode)1367 unsigned TLVstore::getIvlen(int mode)
1368 {
1369 switch (mode)
1370 {
1371 case AES_CCM_12_16:
1372 case AES_GCM_12_16_BROKEN:
1373 case AES_GCM_12_16:
1374 return 12;
1375
1376 case AES_CCM_10_08:
1377 case AES_GCM_10_08_BROKEN:
1378 case AES_CCM_10_16:
1379 case AES_GCM_10_08:
1380 return 10;
1381
1382 default: // unknown block encryption mode
1383 return 0;
1384 }
1385 }
1386
getMode(int mode)1387 encryptionmode_t TLVstore::getMode(int mode)
1388 {
1389 switch (mode)
1390 {
1391 case AES_CCM_12_16:
1392 case AES_GCM_12_16_BROKEN:
1393 case AES_CCM_10_16:
1394 case AES_CCM_10_08:
1395 case AES_GCM_10_08_BROKEN:
1396 return AES_MODE_CCM;
1397
1398 case AES_GCM_12_16:
1399 case AES_GCM_10_08:
1400 return AES_MODE_GCM;
1401
1402 default: // unknown block encryption mode
1403 return AES_MODE_UNKNOWN;
1404 }
1405 }
1406
containerToTLVrecords(const string * data)1407 TLVstore * TLVstore::containerToTLVrecords(const string *data)
1408 {
1409 if (data->empty())
1410 {
1411 return NULL;
1412 }
1413
1414 TLVstore *tlv = new TLVstore();
1415
1416 size_t offset = 0;
1417
1418 string type;
1419 size_t typelen;
1420 string value;
1421 unsigned valuelen;
1422 size_t pos;
1423
1424 size_t datalen = data->length();
1425
1426 while (offset < datalen)
1427 {
1428 // get the length of the Type string
1429 pos = data->find('\0', offset);
1430 typelen = pos - offset;
1431
1432 // if no valid TLV record in the container, but remaining bytes...
1433 if (pos == string::npos || offset + typelen + 3 > datalen)
1434 {
1435 delete tlv;
1436 return NULL;
1437 }
1438
1439 // get the Type string
1440 type.assign((char*)&(data->data()[offset]), typelen);
1441 offset += typelen + 1; // +1: NULL character
1442
1443 // get the Length of the value
1444 valuelen = (unsigned char)data->at(offset) << 8
1445 | (unsigned char)data->at(offset + 1);
1446 offset += 2;
1447
1448 // if there's not enough data for value...
1449 if (offset + valuelen > datalen)
1450 {
1451 delete tlv;
1452 return NULL;
1453 }
1454
1455 // get the Value
1456 value.assign((char*)&(data->data()[offset]), valuelen); // value may include NULL characters, read as a buffer
1457 offset += valuelen;
1458
1459 // add it to the map
1460 tlv->set(type, value);
1461 }
1462
1463 return tlv;
1464 }
1465
1466
containerToTLVrecords(const string * data,SymmCipher * key)1467 TLVstore * TLVstore::containerToTLVrecords(const string *data, SymmCipher *key)
1468 {
1469 if (data->empty())
1470 {
1471 return NULL;
1472 }
1473
1474 unsigned offset = 0;
1475 encryptionsetting_t encSetting = (encryptionsetting_t) data->at(offset);
1476 offset++;
1477
1478 unsigned ivlen = TLVstore::getIvlen(encSetting);
1479 unsigned taglen = TLVstore::getTaglen(encSetting);
1480 encryptionmode_t encMode = TLVstore::getMode(encSetting);
1481
1482 if (encMode == AES_MODE_UNKNOWN || !ivlen || !taglen || data->size() < offset+ivlen+taglen)
1483 {
1484 return NULL;
1485 }
1486
1487 byte *iv = new byte[ivlen];
1488 memcpy(iv, &(data->data()[offset]), ivlen);
1489 offset += ivlen;
1490
1491 unsigned cipherTextLen = unsigned(data->length() - offset);
1492 string cipherText = data->substr(offset, cipherTextLen);
1493
1494 unsigned clearTextLen = cipherTextLen - taglen;
1495 string clearText;
1496
1497 bool decrypted = false;
1498 if (encMode == AES_MODE_CCM) // CCM or GCM_BROKEN (same than CCM)
1499 {
1500 decrypted = key->ccm_decrypt(&cipherText, iv, ivlen, taglen, &clearText);
1501 }
1502 else if (encMode == AES_MODE_GCM) // GCM
1503 {
1504 decrypted = key->gcm_decrypt(&cipherText, iv, ivlen, taglen, &clearText);
1505 }
1506
1507 delete [] iv;
1508
1509 if (!decrypted) // the decryption has failed (probably due to authentication)
1510 {
1511 return NULL;
1512 }
1513 else if (clearText.empty()) // If decryption succeeded but attribute is empty, generate an empty TLV
1514 {
1515 return new TLVstore();
1516 }
1517
1518 TLVstore *tlv = TLVstore::containerToTLVrecords(&clearText);
1519 if (!tlv) // 'data' might be affected by the legacy bug: strings encoded in UTF-8 instead of Unicode
1520 {
1521 // retry TLV decoding after conversion from 'UTF-8 chars' to 'Unicode chars'
1522 LOG_warn << "Retrying TLV records decoding with UTF-8 patch";
1523
1524 string clearTextUnicode;
1525 if (!Utils::utf8toUnicode((const byte*)clearText.data(), clearTextLen, &clearTextUnicode))
1526 {
1527 LOG_err << "Invalid UTF-8 encoding";
1528 }
1529 else
1530 {
1531 tlv = TLVstore::containerToTLVrecords(&clearTextUnicode);
1532 }
1533 }
1534
1535 return tlv;
1536 }
1537
~TLVstore()1538 TLVstore::~TLVstore()
1539 {
1540 }
1541
utf8SequenceSize(unsigned char c)1542 size_t Utils::utf8SequenceSize(unsigned char c)
1543 {
1544 int aux = static_cast<int>(c);
1545 if (aux >= 0 && aux <= 127) return 1;
1546 else if ((aux & 0xE0) == 0xC0) return 2;
1547 else if ((aux & 0xF0) == 0xE0) return 3;
1548 else if ((aux & 0xF8) == 0xF0) return 4;
1549 else
1550 {
1551 LOG_err << "Malformed UTF-8 sequence, interpret character " << c << " as literal";
1552 return 1;
1553 }
1554 }
1555
utf8toUnicode(const uint8_t * src,unsigned srclen,string * result)1556 bool Utils::utf8toUnicode(const uint8_t *src, unsigned srclen, string *result)
1557 {
1558 uint8_t utf8cp1;
1559 uint8_t utf8cp2;
1560 int32_t unicodecp;
1561
1562 if (!srclen)
1563 {
1564 result->clear();
1565 return true;
1566 }
1567
1568 byte *res = new byte[srclen];
1569 unsigned rescount = 0;
1570
1571 unsigned i = 0;
1572 while (i < srclen)
1573 {
1574 utf8cp1 = src[i++];
1575
1576 if (utf8cp1 < 0x80)
1577 {
1578 res[rescount++] = utf8cp1;
1579 }
1580 else
1581 {
1582 if (i < srclen)
1583 {
1584 utf8cp2 = src[i++];
1585
1586 // check codepoints are valid
1587 if ((utf8cp1 == 0xC2 || utf8cp1 == 0xC3) && utf8cp2 >= 0x80 && utf8cp2 <= 0xBF)
1588 {
1589 unicodecp = ((utf8cp1 & 0x1F) << 6) + (utf8cp2 & 0x3F);
1590 res[rescount++] = unicodecp & 0xFF;
1591 }
1592 else
1593 {
1594 // error: one of the two-bytes UTF-8 char is not a valid UTF-8 char
1595 delete [] res;
1596 return false;
1597 }
1598 }
1599 else
1600 {
1601 // error: last byte indicates a two-bytes UTF-8 char, but only one left
1602 delete [] res;
1603 return false;
1604 }
1605 }
1606 }
1607
1608 result->assign((const char*)res, rescount);
1609 delete [] res;
1610
1611 return true;
1612 }
1613
stringToHex(const std::string & input)1614 std::string Utils::stringToHex(const std::string &input)
1615 {
1616 static const char* const lut = "0123456789ABCDEF";
1617 size_t len = input.length();
1618
1619 std::string output;
1620 output.reserve(2 * len);
1621 for (size_t i = 0; i < len; ++i)
1622 {
1623 const unsigned char c = input[i];
1624 output.push_back(lut[c >> 4]);
1625 output.push_back(lut[c & 15]);
1626 }
1627 return output;
1628 }
1629
hexToString(const std::string & input)1630 std::string Utils::hexToString(const std::string &input)
1631 {
1632 static const char* const lut = "0123456789ABCDEF";
1633 size_t len = input.length();
1634 if (len & 1) throw std::invalid_argument("odd length");
1635
1636 std::string output;
1637 output.reserve(len / 2);
1638 for (size_t i = 0; i < len; i += 2)
1639 {
1640 char a = input[i];
1641 const char* p = std::lower_bound(lut, lut + 16, a);
1642 if (*p != a) throw std::invalid_argument("not a hex digit");
1643
1644 char b = input[i + 1];
1645 const char* q = std::lower_bound(lut, lut + 16, b);
1646 if (*q != b) throw std::invalid_argument("not a hex digit");
1647
1648 output.push_back(static_cast<char>(((p - lut) << 4) | (q - lut)));
1649 }
1650 return output;
1651 }
1652
abs(long long n)1653 long long abs(long long n)
1654 {
1655 // for pre-c++11 where this version is not defined yet
1656 return n >= 0 ? n : -n;
1657 }
1658
m_localtime(m_time_t ttime,struct tm * dt)1659 struct tm* m_localtime(m_time_t ttime, struct tm *dt)
1660 {
1661 // works for 32 or 64 bit time_t
1662 time_t t = time_t(ttime);
1663 #if (__cplusplus >= 201103L) && defined (__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)
1664 localtime_s(&t, dt);
1665 #elif _MSC_VER >= 1400 || defined(__MINGW32__) // MSVCRT (2005+): std::localtime is threadsafe
1666 struct tm *newtm = localtime(&t);
1667 if (newtm)
1668 {
1669 memcpy(dt, newtm, sizeof(struct tm));
1670 }
1671 else
1672 {
1673 memset(dt, 0, sizeof(struct tm));
1674 }
1675 #elif _WIN32
1676 #error "localtime is not thread safe in this compiler; please use a later one"
1677 #else //POSIX
1678 localtime_r(&t, dt);
1679 #endif
1680 return dt;
1681 }
1682
m_gmtime(m_time_t ttime,struct tm * dt)1683 struct tm* m_gmtime(m_time_t ttime, struct tm *dt)
1684 {
1685 // works for 32 or 64 bit time_t
1686 time_t t = time_t(ttime);
1687 #if (__cplusplus >= 201103L) && defined (__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)
1688 gmtime_s(&t, dt);
1689 #elif _MSC_VER >= 1400 || defined(__MINGW32__) // MSVCRT (2005+): std::gmtime is threadsafe
1690 struct tm *newtm = gmtime(&t);
1691 if (newtm)
1692 {
1693 memcpy(dt, newtm, sizeof(struct tm));
1694 }
1695 else
1696 {
1697 memset(dt, 0, sizeof(struct tm));
1698 }
1699 #elif _WIN32
1700 #error "gmtime is not thread safe in this compiler; please use a later one"
1701 #else //POSIX
1702 gmtime_r(&t, dt);
1703 #endif
1704 return dt;
1705 }
1706
m_time(m_time_t * tt)1707 m_time_t m_time(m_time_t* tt)
1708 {
1709 // works for 32 or 64 bit time_t
1710 time_t t = time(NULL);
1711 if (tt)
1712 {
1713 *tt = t;
1714 }
1715 return t;
1716 }
1717
m_mktime(struct tm * stm)1718 m_time_t m_mktime(struct tm* stm)
1719 {
1720 // works for 32 or 64 bit time_t
1721 return mktime(stm);
1722 }
1723
m_clock_getmonotonictime(timespec * t)1724 int m_clock_getmonotonictime(timespec *t)
1725 {
1726 #ifdef __APPLE__
1727 struct timeval now;
1728 int rv = gettimeofday(&now, NULL);
1729 if (rv)
1730 {
1731 return rv;
1732 }
1733 t->tv_sec = now.tv_sec;
1734 t->tv_nsec = now.tv_usec * 1000;
1735 return 0;
1736 #elif defined(_WIN32) && defined(_MSC_VER)
1737 struct __timeb64 tb;
1738 _ftime64(&tb);
1739 t->tv_sec = tb.time;
1740 t->tv_nsec = long(tb.millitm) * 1000000;
1741 return 0;
1742 #else
1743 #ifdef CLOCK_BOOTTIME
1744 return clock_gettime(CLOCK_BOOTTIME, t);
1745 #else
1746 return clock_gettime(CLOCK_MONOTONIC, t);
1747 #endif
1748 #endif
1749
1750 }
1751
m_mktime_UTC(const struct tm * src)1752 m_time_t m_mktime_UTC(const struct tm *src)
1753 {
1754 struct tm dst = *src;
1755 m_time_t t = 0;
1756 #if _MSC_VER >= 1400 || defined(__MINGW32__) // MSVCRT (2005+)
1757 t = mktime(&dst);
1758 TIME_ZONE_INFORMATION TimeZoneInfo;
1759 GetTimeZoneInformation(&TimeZoneInfo);
1760 t += TimeZoneInfo.Bias * 60 - dst.tm_isdst * 3600;
1761 #elif _WIN32
1762 #error "localtime is not thread safe in this compiler; please use a later one"
1763 #else //POSIX
1764 t = mktime(&dst);
1765 t += dst.tm_gmtoff - dst.tm_isdst * 3600;
1766 #endif
1767 return t;
1768 }
1769
rfc1123_datetime(time_t time)1770 std::string rfc1123_datetime( time_t time )
1771 {
1772 struct tm * timeinfo;
1773 char buffer [80];
1774 timeinfo = gmtime(&time);
1775 strftime (buffer, 80, "%a, %d %b %Y %H:%M:%S GMT",timeinfo);
1776 return buffer;
1777 }
1778
webdavurlescape(const string & value)1779 string webdavurlescape(const string &value)
1780 {
1781 ostringstream escaped;
1782 escaped.fill('0');
1783 escaped << std::hex;
1784
1785 for (string::const_iterator i = value.begin(), n = value.end(); i != n; ++i)
1786 {
1787 string::value_type c = (*i);
1788 if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || c == '/' || c == ':')
1789 {
1790 escaped << c;
1791 }
1792 else
1793 {
1794 escaped << std::uppercase;
1795 escaped << '%' << std::setw(2) << int((unsigned char) c);
1796 escaped << std::nouppercase;
1797 }
1798 }
1799
1800 return escaped.str();
1801 }
1802
escapewebdavchar(const char c)1803 string escapewebdavchar(const char c)
1804 {
1805 static bool unintitialized = true;
1806 static std::map<int,const char *> escapesec;
1807 if (unintitialized)
1808 {
1809 escapesec[33] = "!"; // ! //For some reason &Exclamation; was not properly handled (crashed) by gvfsd-dav
1810 escapesec[34] = """; // "
1811 escapesec[37] = "%"; // %
1812 escapesec[38] = "&"; // &
1813 escapesec[39] = "'"; // '
1814 escapesec[43] = "&add;"; // +
1815 escapesec[60] = "<"; // <
1816 escapesec[61] = "="; // = //For some reason &equal; was not properly handled (crashed) by gvfsd-dav
1817 escapesec[62] = ">"; // >
1818 escapesec[160] = " "; //NO-BREAK SPACE
1819 escapesec[161] = "¡"; //INVERTED EXCLAMATION MARK
1820 escapesec[162] = "¢"; //CENT SIGN
1821 escapesec[163] = "£"; //POUND SIGN
1822 escapesec[164] = "¤"; //CURRENCY SIGN
1823 escapesec[165] = "¥"; //YEN SIGN
1824 escapesec[166] = "¦"; //BROKEN BAR
1825 escapesec[167] = "§"; //SECTION SIGN
1826 escapesec[168] = "¨"; //DIAERESIS
1827 escapesec[169] = "©"; //COPYRIGHT SIGN
1828 escapesec[170] = "ª"; //FEMININE ORDINAL INDICATOR
1829 escapesec[171] = "«"; //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
1830 escapesec[172] = "¬"; //NOT SIGN
1831 escapesec[173] = "­"; //SOFT HYPHEN
1832 escapesec[174] = "®"; //REGISTERED SIGN
1833 escapesec[175] = "¯"; //MACRON
1834 escapesec[176] = "°"; //DEGREE SIGN
1835 escapesec[177] = "±"; //PLUS-MINUS SIGN
1836 escapesec[178] = "²"; //SUPERSCRIPT TWO
1837 escapesec[179] = "³"; //SUPERSCRIPT THREE
1838 escapesec[180] = "´"; //ACUTE ACCENT
1839 escapesec[181] = "µ"; //MICRO SIGN
1840 escapesec[182] = "¶"; //PILCROW SIGN
1841 escapesec[183] = "·"; //MIDDLE DOT
1842 escapesec[184] = "¸"; //CEDILLA
1843 escapesec[185] = "¹"; //SUPERSCRIPT ONE
1844 escapesec[186] = "º"; //MASCULINE ORDINAL INDICATOR
1845 escapesec[187] = "»"; //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
1846 escapesec[188] = "¼"; //VULGAR FRACTION ONE QUARTER
1847 escapesec[189] = "½"; //VULGAR FRACTION ONE HALF
1848 escapesec[190] = "¾"; //VULGAR FRACTION THREE QUARTERS
1849 escapesec[191] = "¿"; //INVERTED QUESTION MARK
1850 escapesec[192] = "À"; //LATIN CAPITAL LETTER A WITH GRAVE
1851 escapesec[193] = "Á"; //LATIN CAPITAL LETTER A WITH ACUTE
1852 escapesec[194] = "Â"; //LATIN CAPITAL LETTER A WITH CIRCUMFLEX
1853 escapesec[195] = "Ã"; //LATIN CAPITAL LETTER A WITH TILDE
1854 escapesec[196] = "Ä"; //LATIN CAPITAL LETTER A WITH DIAERESIS
1855 escapesec[197] = "Å"; //LATIN CAPITAL LETTER A WITH RING ABOVE
1856 escapesec[198] = "Æ"; //LATIN CAPITAL LETTER AE
1857 escapesec[199] = "Ç"; //LATIN CAPITAL LETTER C WITH CEDILLA
1858 escapesec[200] = "È"; //LATIN CAPITAL LETTER E WITH GRAVE
1859 escapesec[201] = "É"; //LATIN CAPITAL LETTER E WITH ACUTE
1860 escapesec[202] = "Ê"; //LATIN CAPITAL LETTER E WITH CIRCUMFLEX
1861 escapesec[203] = "Ë"; //LATIN CAPITAL LETTER E WITH DIAERESIS
1862 escapesec[204] = "Ì"; //LATIN CAPITAL LETTER I WITH GRAVE
1863 escapesec[205] = "Í"; //LATIN CAPITAL LETTER I WITH ACUTE
1864 escapesec[206] = "Î"; //LATIN CAPITAL LETTER I WITH CIRCUMFLEX
1865 escapesec[207] = "Ï"; //LATIN CAPITAL LETTER I WITH DIAERESIS
1866 escapesec[208] = "Ð"; //LATIN CAPITAL LETTER ETH
1867 escapesec[209] = "Ñ"; //LATIN CAPITAL LETTER N WITH TILDE
1868 escapesec[210] = "Ò"; //LATIN CAPITAL LETTER O WITH GRAVE
1869 escapesec[211] = "Ó"; //LATIN CAPITAL LETTER O WITH ACUTE
1870 escapesec[212] = "Ô"; //LATIN CAPITAL LETTER O WITH CIRCUMFLEX
1871 escapesec[213] = "Õ"; //LATIN CAPITAL LETTER O WITH TILDE
1872 escapesec[214] = "Ö"; //LATIN CAPITAL LETTER O WITH DIAERESIS
1873 escapesec[215] = "×"; //MULTIPLICATION SIGN
1874 escapesec[216] = "Ø"; //LATIN CAPITAL LETTER O WITH STROKE
1875 escapesec[217] = "Ù"; //LATIN CAPITAL LETTER U WITH GRAVE
1876 escapesec[218] = "Ú"; //LATIN CAPITAL LETTER U WITH ACUTE
1877 escapesec[219] = "Û"; //LATIN CAPITAL LETTER U WITH CIRCUMFLEX
1878 escapesec[220] = "Ü"; //LATIN CAPITAL LETTER U WITH DIAERESIS
1879 escapesec[221] = "Ý"; //LATIN CAPITAL LETTER Y WITH ACUTE
1880 escapesec[222] = "Þ"; //LATIN CAPITAL LETTER THORN
1881 escapesec[223] = "ß"; //LATIN SMALL LETTER SHARP S
1882 escapesec[224] = "à"; //LATIN SMALL LETTER A WITH GRAVE
1883 escapesec[225] = "á"; //LATIN SMALL LETTER A WITH ACUTE
1884 escapesec[226] = "â"; //LATIN SMALL LETTER A WITH CIRCUMFLEX
1885 escapesec[227] = "ã"; //LATIN SMALL LETTER A WITH TILDE
1886 escapesec[228] = "ä"; //LATIN SMALL LETTER A WITH DIAERESIS
1887 escapesec[229] = "å"; //LATIN SMALL LETTER A WITH RING ABOVE
1888 escapesec[230] = "æ"; //LATIN SMALL LETTER AE
1889 escapesec[231] = "ç"; //LATIN SMALL LETTER C WITH CEDILLA
1890 escapesec[232] = "è"; //LATIN SMALL LETTER E WITH GRAVE
1891 escapesec[233] = "é"; //LATIN SMALL LETTER E WITH ACUTE
1892 escapesec[234] = "ê"; //LATIN SMALL LETTER E WITH CIRCUMFLEX
1893 escapesec[235] = "ë"; //LATIN SMALL LETTER E WITH DIAERESIS
1894 escapesec[236] = "ì"; //LATIN SMALL LETTER I WITH GRAVE
1895 escapesec[237] = "í"; //LATIN SMALL LETTER I WITH ACUTE
1896 escapesec[238] = "î"; //LATIN SMALL LETTER I WITH CIRCUMFLEX
1897 escapesec[239] = "ï"; //LATIN SMALL LETTER I WITH DIAERESIS
1898 escapesec[240] = "ð"; //LATIN SMALL LETTER ETH
1899 escapesec[241] = "ñ"; //LATIN SMALL LETTER N WITH TILDE
1900 escapesec[242] = "ò"; //LATIN SMALL LETTER O WITH GRAVE
1901 escapesec[243] = "ó"; //LATIN SMALL LETTER O WITH ACUTE
1902 escapesec[244] = "ô"; //LATIN SMALL LETTER O WITH CIRCUMFLEX
1903 escapesec[245] = "õ"; //LATIN SMALL LETTER O WITH TILDE
1904 escapesec[246] = "ö"; //LATIN SMALL LETTER O WITH DIAERESIS
1905 escapesec[247] = "÷"; //DIVISION SIGN
1906 escapesec[248] = "ø"; //LATIN SMALL LETTER O WITH STROKE
1907 escapesec[249] = "ù"; //LATIN SMALL LETTER U WITH GRAVE
1908 escapesec[250] = "ú"; //LATIN SMALL LETTER U WITH ACUTE
1909 escapesec[251] = "û"; //LATIN SMALL LETTER U WITH CIRCUMFLEX
1910 escapesec[252] = "ü"; //LATIN SMALL LETTER U WITH DIAERESIS
1911 escapesec[253] = "ý"; //LATIN SMALL LETTER Y WITH ACUTE
1912 escapesec[254] = "þ"; //LATIN SMALL LETTER THORN
1913 escapesec[255] = "ÿ"; //LATIN SMALL LETTER Y WITH DIAERESIS
1914 escapesec[338] = "Œ"; //LATIN CAPITAL LIGATURE OE
1915 escapesec[339] = "œ"; //LATIN SMALL LIGATURE OE
1916 escapesec[352] = "Š"; //LATIN CAPITAL LETTER S WITH CARON
1917 escapesec[353] = "š"; //LATIN SMALL LETTER S WITH CARON
1918 escapesec[376] = "Ÿ"; //LATIN CAPITAL LETTER Y WITH DIAERESIS
1919 escapesec[402] = "ƒ"; //LATIN SMALL LETTER F WITH HOOK
1920 escapesec[710] = "ˆ"; //MODIFIER LETTER CIRCUMFLEX ACCENT
1921 escapesec[732] = "˜"; //SMALL TILDE
1922 escapesec[913] = "Α"; //GREEK CAPITAL LETTER ALPHA
1923 escapesec[914] = "Β"; //GREEK CAPITAL LETTER BETA
1924 escapesec[915] = "Γ"; //GREEK CAPITAL LETTER GAMMA
1925 escapesec[916] = "Δ"; //GREEK CAPITAL LETTER DELTA
1926 escapesec[917] = "Ε"; //GREEK CAPITAL LETTER EPSILON
1927 escapesec[918] = "Ζ"; //GREEK CAPITAL LETTER ZETA
1928 escapesec[919] = "Η"; //GREEK CAPITAL LETTER ETA
1929 escapesec[920] = "Θ"; //GREEK CAPITAL LETTER THETA
1930 escapesec[921] = "Ι"; //GREEK CAPITAL LETTER IOTA
1931 escapesec[922] = "Κ"; //GREEK CAPITAL LETTER KAPPA
1932 escapesec[923] = "Λ"; //GREEK CAPITAL LETTER LAMDA
1933 escapesec[924] = "Μ"; //GREEK CAPITAL LETTER MU
1934 escapesec[925] = "Ν"; //GREEK CAPITAL LETTER NU
1935 escapesec[926] = "Ξ"; //GREEK CAPITAL LETTER XI
1936 escapesec[927] = "Ο"; //GREEK CAPITAL LETTER OMICRON
1937 escapesec[928] = "Π"; //GREEK CAPITAL LETTER PI
1938 escapesec[929] = "Ρ"; //GREEK CAPITAL LETTER RHO
1939 escapesec[931] = "Σ"; //GREEK CAPITAL LETTER SIGMA
1940 escapesec[932] = "Τ"; //GREEK CAPITAL LETTER TAU
1941 escapesec[933] = "Υ"; //GREEK CAPITAL LETTER UPSILON
1942 escapesec[934] = "Φ"; //GREEK CAPITAL LETTER PHI
1943 escapesec[935] = "Χ"; //GREEK CAPITAL LETTER CHI
1944 escapesec[936] = "Ψ"; //GREEK CAPITAL LETTER PSI
1945 escapesec[937] = "Ω"; //GREEK CAPITAL LETTER OMEGA
1946 escapesec[945] = "α"; //GREEK SMALL LETTER ALPHA
1947 escapesec[946] = "β"; //GREEK SMALL LETTER BETA
1948 escapesec[947] = "γ"; //GREEK SMALL LETTER GAMMA
1949 escapesec[948] = "δ"; //GREEK SMALL LETTER DELTA
1950 escapesec[949] = "ε"; //GREEK SMALL LETTER EPSILON
1951 escapesec[950] = "ζ"; //GREEK SMALL LETTER ZETA
1952 escapesec[951] = "η"; //GREEK SMALL LETTER ETA
1953 escapesec[952] = "θ"; //GREEK SMALL LETTER THETA
1954 escapesec[953] = "ι"; //GREEK SMALL LETTER IOTA
1955 escapesec[954] = "κ"; //GREEK SMALL LETTER KAPPA
1956 escapesec[955] = "λ"; //GREEK SMALL LETTER LAMDA
1957 escapesec[956] = "μ"; //GREEK SMALL LETTER MU
1958 escapesec[957] = "ν"; //GREEK SMALL LETTER NU
1959 escapesec[958] = "ξ"; //GREEK SMALL LETTER XI
1960 escapesec[959] = "ο"; //GREEK SMALL LETTER OMICRON
1961 escapesec[960] = "π"; //GREEK SMALL LETTER PI
1962 escapesec[961] = "ρ"; //GREEK SMALL LETTER RHO
1963 escapesec[962] = "ς"; //GREEK SMALL LETTER FINAL SIGMA
1964 escapesec[963] = "σ"; //GREEK SMALL LETTER SIGMA
1965 escapesec[964] = "τ"; //GREEK SMALL LETTER TAU
1966 escapesec[965] = "υ"; //GREEK SMALL LETTER UPSILON
1967 escapesec[966] = "φ"; //GREEK SMALL LETTER PHI
1968 escapesec[967] = "χ"; //GREEK SMALL LETTER CHI
1969 escapesec[968] = "ψ"; //GREEK SMALL LETTER PSI
1970 escapesec[969] = "ω"; //GREEK SMALL LETTER OMEGA
1971 escapesec[977] = "ϑ"; //GREEK THETA SYMBOL
1972 escapesec[978] = "ϒ"; //GREEK UPSILON WITH HOOK SYMBOL
1973 escapesec[982] = "ϖ"; //GREEK PI SYMBOL
1974 escapesec[8194] = " "; //EN SPACE
1975 escapesec[8195] = " "; //EM SPACE
1976 escapesec[8201] = " "; //THIN SPACE
1977 escapesec[8204] = "‌"; //ZERO WIDTH NON-JOINER
1978 escapesec[8205] = "‍"; //ZERO WIDTH JOINER
1979 escapesec[8206] = "‎"; //LEFT-TO-RIGHT MARK
1980 escapesec[8207] = "‏"; //RIGHT-TO-LEFT MARK
1981 escapesec[8211] = "–"; //EN DASH
1982 escapesec[8212] = "—"; //EM DASH
1983 escapesec[8213] = "―"; //HORIZONTAL BAR
1984 escapesec[8216] = "‘"; //LEFT SINGLE QUOTATION MARK
1985 escapesec[8217] = "’"; //RIGHT SINGLE QUOTATION MARK
1986 escapesec[8218] = "‚"; //SINGLE LOW-9 QUOTATION MARK
1987 escapesec[8220] = "“"; //LEFT DOUBLE QUOTATION MARK
1988 escapesec[8221] = "”"; //RIGHT DOUBLE QUOTATION MARK
1989 escapesec[8222] = "„"; //DOUBLE LOW-9 QUOTATION MARK
1990 escapesec[8224] = "†"; //DAGGER
1991 escapesec[8225] = "‡"; //DOUBLE DAGGER
1992 escapesec[8226] = "•"; //BULLET
1993 escapesec[8230] = "…"; //HORIZONTAL ELLIPSIS
1994 escapesec[8240] = "‰"; //PER MILLE SIGN
1995 escapesec[8242] = "′"; //PRIME
1996 escapesec[8243] = "″"; //DOUBLE PRIME
1997 escapesec[8249] = "‹"; //SINGLE LEFT-POINTING ANGLE QUOTATION MARK
1998 escapesec[8250] = "›"; //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
1999 escapesec[8254] = "‾"; //OVERLINE
2000 escapesec[8260] = "⁄"; //FRACTION SLASH
2001 escapesec[8364] = "€"; //EURO SIGN
2002 escapesec[8465] = "ℑ"; //BLACK-LETTER CAPITAL I
2003 escapesec[8472] = "℘"; //SCRIPT CAPITAL P
2004 escapesec[8476] = "ℜ"; //BLACK-LETTER CAPITAL R
2005 escapesec[8482] = "™"; //TRADE MARK SIGN
2006 escapesec[8501] = "ℵ"; //ALEF SYMBOL
2007 escapesec[8592] = "←"; //LEFTWARDS ARROW
2008 escapesec[8593] = "↑"; //UPWARDS ARROW
2009 escapesec[8594] = "→"; //RIGHTWARDS ARROW
2010 escapesec[8595] = "↓"; //DOWNWARDS ARROW
2011 escapesec[8596] = "↔"; //LEFT RIGHT ARROW
2012 escapesec[8629] = "↵"; //DOWNWARDS ARROW WITH CORNER LEFTWARDS
2013 escapesec[8656] = "⇐"; //LEFTWARDS DOUBLE ARROW
2014 escapesec[8657] = "⇑"; //UPWARDS DOUBLE ARROW
2015 escapesec[8658] = "⇒"; //RIGHTWARDS DOUBLE ARROW
2016 escapesec[8659] = "⇓"; //DOWNWARDS DOUBLE ARROW
2017 escapesec[8660] = "⇔"; //LEFT RIGHT DOUBLE ARROW
2018 escapesec[8704] = "∀"; //FOR ALL
2019 escapesec[8706] = "∂"; //PARTIAL DIFFERENTIAL
2020 escapesec[8707] = "∃"; //THERE EXISTS
2021 escapesec[8709] = "∅"; //EMPTY SET
2022 escapesec[8711] = "∇"; //NABLA
2023 escapesec[8712] = "∈"; //ELEMENT OF
2024 escapesec[8713] = "∉"; //NOT AN ELEMENT OF
2025 escapesec[8715] = "∋"; //CONTAINS AS MEMBER
2026 escapesec[8719] = "∏"; //N-ARY PRODUCT
2027 escapesec[8721] = "∑"; //N-ARY SUMMATION
2028 escapesec[8722] = "−"; //MINUS SIGN
2029 escapesec[8727] = "∗"; //ASTERISK OPERATOR
2030 escapesec[8730] = "√"; //SQUARE ROOT
2031 escapesec[8733] = "∝"; //PROPORTIONAL TO
2032 escapesec[8734] = "∞"; //INFINITY
2033 escapesec[8736] = "∠"; //ANGLE
2034 escapesec[8743] = "∧"; //LOGICAL AND
2035 escapesec[8744] = "∨"; //LOGICAL OR
2036 escapesec[8745] = "∩"; //INTERSECTION
2037 escapesec[8746] = "∪"; //UNION
2038 escapesec[8747] = "∫"; //INTEGRAL
2039 escapesec[8756] = "∴"; //THEREFORE
2040 escapesec[8764] = "∼"; //TILDE OPERATOR
2041 escapesec[8773] = "≅"; //APPROXIMATELY EQUAL TO
2042 escapesec[8776] = "≈"; //ALMOST EQUAL TO
2043 escapesec[8800] = "≠"; //NOT EQUAL TO
2044 escapesec[8801] = "≡"; //IDENTICAL TO
2045 escapesec[8804] = "≤"; //LESS-THAN OR EQUAL TO
2046 escapesec[8805] = "≥"; //GREATER-THAN OR EQUAL TO
2047 escapesec[8834] = "⊂"; //SUBSET OF
2048 escapesec[8835] = "⊃"; //SUPERSET OF
2049 escapesec[8836] = "⊄"; //NOT A SUBSET OF
2050 escapesec[8838] = "⊆"; //SUBSET OF OR EQUAL TO
2051 escapesec[8839] = "⊇"; //SUPERSET OF OR EQUAL TO
2052 escapesec[8853] = "⊕"; //CIRCLED PLUS
2053 escapesec[8855] = "⊗"; //CIRCLED TIMES
2054 escapesec[8869] = "⊥"; //UP TACK
2055 escapesec[8901] = "⋅"; //DOT OPERATOR
2056 escapesec[8968] = "⌈"; //LEFT CEILING
2057 escapesec[8969] = "⌉"; //RIGHT CEILING
2058 escapesec[8970] = "⌊"; //LEFT FLOOR
2059 escapesec[8971] = "⌋"; //RIGHT FLOOR
2060 escapesec[9001] = "⟨"; //LEFT-POINTING ANGLE BRACKET
2061 escapesec[9002] = "⟩"; //RIGHT-POINTING ANGLE BRACKET
2062 escapesec[9674] = "◊"; //LOZENGE
2063 escapesec[9824] = "♠"; //BLACK SPADE SUIT
2064 escapesec[9827] = "♣"; //BLACK CLUB SUIT
2065 escapesec[9829] = "♥"; //BLACK HEART SUIT
2066 escapesec[9830] = "♦"; //BLACK DIAMOND SUIT
2067
2068 unintitialized = false;
2069 }
2070 if (escapesec.find(c) != escapesec.end())
2071 {
2072 return escapesec[c];
2073 }
2074
2075 return string(1,c);
2076 }
2077
webdavnameescape(const string & value)2078 string webdavnameescape(const string &value) {
2079 ostringstream escaped;
2080
2081 for (string::const_iterator i = value.begin(), n = value.end(); i != n; ++i)
2082 {
2083 escaped << escapewebdavchar(*i);
2084 }
2085
2086 return escaped.str();
2087 }
2088
tolower_string(std::string & str)2089 void tolower_string(std::string& str)
2090 {
2091 std::transform(str.begin(), str.end(), str.begin(), [](char c) {return static_cast<char>(::tolower(c)); });
2092 }
2093
2094 #ifdef __APPLE__
macOSmajorVersion()2095 int macOSmajorVersion()
2096 {
2097 char releaseStr[256];
2098 size_t size = sizeof(releaseStr);
2099 if (!sysctlbyname("kern.osrelease", releaseStr, &size, NULL, 0) && size > 0)
2100 {
2101 if (strchr(releaseStr,'.'))
2102 {
2103 char *token = strtok(releaseStr, ".");
2104 if (token)
2105 {
2106 errno = 0;
2107 char *endPtr = NULL;
2108 long majorVersion = strtol(token, &endPtr, 10);
2109 if (endPtr != token && errno != ERANGE && majorVersion >= INT_MIN && majorVersion <= INT_MAX)
2110 {
2111 return int(majorVersion);
2112 }
2113 }
2114 }
2115 }
2116
2117 return -1;
2118 }
2119 #endif
2120
operator +=(const NodeCounter & o)2121 void NodeCounter::operator += (const NodeCounter& o)
2122 {
2123 storage += o.storage;
2124 versionStorage += o.versionStorage;
2125 files += o.files;
2126 folders += o.folders;
2127 versions += o.versions;
2128 }
2129
operator -=(const NodeCounter & o)2130 void NodeCounter::operator -= (const NodeCounter& o)
2131 {
2132 storage -= o.storage;
2133 versionStorage -= o.versionStorage;
2134 files -= o.files;
2135 folders -= o.folders;
2136 versions -= o.versions;
2137 }
2138
SyncConfig(std::string localPath,const handle remoteNode,const fsfp_t localFingerprint,std::vector<std::string> regExps,const Type syncType,const bool syncDeletions,const bool forceOverwrite)2139 SyncConfig::SyncConfig(std::string localPath,
2140 const handle remoteNode,
2141 const fsfp_t localFingerprint,
2142 std::vector<std::string> regExps,
2143 const Type syncType,
2144 const bool syncDeletions,
2145 const bool forceOverwrite)
2146 : mLocalPath{std::move(localPath)}
2147 , mRemoteNode{remoteNode}
2148 , mLocalFingerprint{localFingerprint}
2149 , mRegExps{std::move(regExps)}
2150 , mSyncType{syncType}
2151 , mSyncDeletions{syncDeletions}
2152 , mForceOverwrite{forceOverwrite}
2153 {}
2154
isResumable() const2155 bool SyncConfig::isResumable() const
2156 {
2157 return mResumable;
2158 }
2159
setResumable(bool resumable)2160 void SyncConfig::setResumable(bool resumable)
2161 {
2162 mResumable = resumable;
2163 }
2164
getLocalPath() const2165 const std::string& SyncConfig::getLocalPath() const
2166 {
2167 return mLocalPath;
2168 }
2169
getRemoteNode() const2170 handle SyncConfig::getRemoteNode() const
2171 {
2172 return mRemoteNode;
2173 }
2174
getLocalFingerprint() const2175 handle SyncConfig::getLocalFingerprint() const
2176 {
2177 return mLocalFingerprint;
2178 }
2179
setLocalFingerprint(fsfp_t fingerprint)2180 void SyncConfig::setLocalFingerprint(fsfp_t fingerprint)
2181 {
2182 mLocalFingerprint = fingerprint;
2183 }
2184
getRegExps() const2185 const std::vector<std::string>& SyncConfig::getRegExps() const
2186 {
2187 return mRegExps;
2188 }
2189
getType() const2190 SyncConfig::Type SyncConfig::getType() const
2191 {
2192 return mSyncType;
2193 }
2194
isUpSync() const2195 bool SyncConfig::isUpSync() const
2196 {
2197 return mSyncType & TYPE_UP;
2198 }
2199
isDownSync() const2200 bool SyncConfig::isDownSync() const
2201 {
2202 return mSyncType & TYPE_DOWN;
2203 }
2204
syncDeletions() const2205 bool SyncConfig::syncDeletions() const
2206 {
2207 switch (mSyncType)
2208 {
2209 case TYPE_UP: return mSyncDeletions;
2210 case TYPE_DOWN: return mSyncDeletions;
2211 case TYPE_TWOWAY: return true;
2212 }
2213 assert(false);
2214 return true;
2215 }
2216
forceOverwrite() const2217 bool SyncConfig::forceOverwrite() const
2218 {
2219 switch (mSyncType)
2220 {
2221 case TYPE_UP: return mForceOverwrite;
2222 case TYPE_DOWN: return mForceOverwrite;
2223 case TYPE_TWOWAY: return false;
2224 }
2225 assert(false);
2226 return false;
2227 }
2228
2229 // This should be a const-method but can't be due to the broken Cacheable interface.
2230 // Do not mutate members in this function! Hence, we forward to a private const-method.
serialize(std::string * data)2231 bool SyncConfig::serialize(std::string* data)
2232 {
2233 return const_cast<const SyncConfig*>(this)->serialize(*data);
2234 }
2235
unserialize(const std::string & data)2236 std::unique_ptr<SyncConfig> SyncConfig::unserialize(const std::string& data)
2237 {
2238 bool resumable;
2239 std::string localPath;
2240 handle remoteNode;
2241 fsfp_t fingerprint;
2242 uint32_t regExpCount;
2243 std::vector<std::string> regExps;
2244 uint32_t syncType;
2245 bool syncDeletions;
2246 bool forceOverwrite;
2247
2248 CacheableReader reader{data};
2249 if (!reader.unserializebool(resumable))
2250 {
2251 return {};
2252 }
2253 if (!reader.unserializestring(localPath))
2254 {
2255 return {};
2256 }
2257 if (!reader.unserializehandle(remoteNode))
2258 {
2259 return {};
2260 }
2261 if (!reader.unserializefsfp(fingerprint))
2262 {
2263 return {};
2264 }
2265 if (!reader.unserializeu32(regExpCount))
2266 {
2267 return {};
2268 }
2269 for (uint32_t i = 0; i < regExpCount; ++i)
2270 {
2271 std::string regExp;
2272 if (!reader.unserializestring(regExp))
2273 {
2274 return {};
2275 }
2276 regExps.push_back(std::move(regExp));
2277 }
2278 if (!reader.unserializeu32(syncType))
2279 {
2280 return {};
2281 }
2282 if (!reader.unserializebool(syncDeletions))
2283 {
2284 return {};
2285 }
2286 if (!reader.unserializebool(forceOverwrite))
2287 {
2288 return {};
2289 }
2290
2291 auto syncConfig = std::unique_ptr<SyncConfig>{new SyncConfig{std::move(localPath),
2292 remoteNode, fingerprint, std::move(regExps),
2293 static_cast<Type>(syncType), syncDeletions, forceOverwrite}};
2294 syncConfig->setResumable(resumable);
2295 return syncConfig;
2296 }
2297
serialize(std::string & data) const2298 bool SyncConfig::serialize(std::string& data) const
2299 {
2300 CacheableWriter writer{data};
2301 writer.serializebool(mResumable);
2302 writer.serializestring(mLocalPath);
2303 writer.serializehandle(mRemoteNode);
2304 writer.serializefsfp(mLocalFingerprint);
2305 writer.serializeu32(static_cast<uint32_t>(mRegExps.size()));
2306 for (const auto& regExp : mRegExps)
2307 {
2308 writer.serializestring(regExp);
2309 }
2310 writer.serializeu32(static_cast<uint32_t>(mSyncType));
2311 writer.serializebool(mSyncDeletions);
2312 writer.serializebool(mForceOverwrite);
2313 writer.serializeexpansionflags();
2314 return true;
2315 }
2316
operator ==(const SyncConfig & lhs,const SyncConfig & rhs)2317 bool operator==(const SyncConfig& lhs, const SyncConfig& rhs)
2318 {
2319 return lhs.tie() == rhs.tie();
2320 }
2321
generateMetaMac(SymmCipher & cipher,FileAccess & ifAccess,const int64_t iv)2322 std::pair<bool, int64_t> generateMetaMac(SymmCipher &cipher, FileAccess &ifAccess, const int64_t iv)
2323 {
2324 FileInputStream isAccess(&ifAccess);
2325
2326 return generateMetaMac(cipher, isAccess, iv);
2327 }
2328
generateMetaMac(SymmCipher & cipher,InputStreamAccess & isAccess,const int64_t iv)2329 std::pair<bool, int64_t> generateMetaMac(SymmCipher &cipher, InputStreamAccess &isAccess, const int64_t iv)
2330 {
2331 static const m_off_t SZ_1024K = 1l << 20;
2332 static const m_off_t SZ_128K = 128l << 10;
2333
2334 std::unique_ptr<byte[]> buffer(new byte[SZ_1024K + SymmCipher::BLOCKSIZE]);
2335 chunkmac_map chunkMacs;
2336 m_off_t chunkLength = 0;
2337 m_off_t current = 0;
2338 m_off_t remaining = isAccess.size();
2339
2340 while (remaining > 0)
2341 {
2342 chunkLength =
2343 std::min(chunkLength + SZ_128K,
2344 std::min(remaining, SZ_1024K));
2345
2346 if (!isAccess.read(&buffer[0], (unsigned int)chunkLength))
2347 return std::make_pair(false, 0l);
2348
2349 memset(&buffer[chunkLength], 0, SymmCipher::BLOCKSIZE);
2350
2351 cipher.ctr_crypt(&buffer[0],
2352 (unsigned int)chunkLength,
2353 current,
2354 iv,
2355 chunkMacs[current].mac,
2356 1);
2357
2358 current += chunkLength;
2359 remaining -= chunkLength;
2360 }
2361
2362 return std::make_pair(true, chunkMacs.macsmac(&cipher));
2363 }
2364
push(std::function<void (SymmCipher &)> f,bool discardable)2365 void MegaClientAsyncQueue::push(std::function<void(SymmCipher&)> f, bool discardable)
2366 {
2367 if (mThreads.empty())
2368 {
2369 if (f)
2370 {
2371 f(mZeroThreadsCipher);
2372 }
2373 }
2374 else
2375 {
2376 {
2377 std::lock_guard<std::mutex> g(mMutex);
2378 mQueue.emplace_back(discardable, std::move(f));
2379 }
2380 mConditionVariable.notify_one();
2381 }
2382 }
2383
MegaClientAsyncQueue(Waiter & w,unsigned threadCount)2384 MegaClientAsyncQueue::MegaClientAsyncQueue(Waiter& w, unsigned threadCount)
2385 : mWaiter(w)
2386 {
2387 for (int i = threadCount; i--; )
2388 {
2389 try
2390 {
2391 mThreads.emplace_back([this]()
2392 {
2393 asyncThreadLoop();
2394 });
2395 }
2396 catch (std::system_error& e)
2397 {
2398 LOG_err << "Failed to start worker thread: " << e.what();
2399 break;
2400 }
2401 }
2402 LOG_debug << "MegaClient Worker threads running: " << mThreads.size();
2403 }
2404
~MegaClientAsyncQueue()2405 MegaClientAsyncQueue::~MegaClientAsyncQueue()
2406 {
2407 clearDiscardable();
2408 push(nullptr, false);
2409 mConditionVariable.notify_all();
2410 LOG_warn << "~MegaClientAsyncQueue() joining threads";
2411 for (auto& t : mThreads)
2412 {
2413 t.join();
2414 }
2415 LOG_warn << "~MegaClientAsyncQueue() ends";
2416 }
2417
clearDiscardable()2418 void MegaClientAsyncQueue::clearDiscardable()
2419 {
2420 std::lock_guard<std::mutex> g(mMutex);
2421 auto newEnd = std::remove_if(mQueue.begin(), mQueue.end(), [](Entry& entry){ return entry.discardable; });
2422 mQueue.erase(newEnd, mQueue.end());
2423 }
2424
asyncThreadLoop()2425 void MegaClientAsyncQueue::asyncThreadLoop()
2426 {
2427 SymmCipher cipher;
2428 for (;;)
2429 {
2430 std::function<void(SymmCipher&)> f;
2431 {
2432 std::unique_lock<std::mutex> g(mMutex);
2433 mConditionVariable.wait(g, [this]() { return !mQueue.empty(); });
2434 f = std::move(mQueue.front().f);
2435 if (!f) return; // nullptr is not popped, and causes all the threads to exit
2436 mQueue.pop_front();
2437 }
2438 f(cipher);
2439 mWaiter.notify();
2440 }
2441 }
2442
2443 } // namespace
2444
2445