1 // This file is part of par2cmdline (a PAR 2.0 compatible file verification and
2 // repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
3 //
4 // Copyright (c) 2003 Peter Brian Clements
5 //
6 // par2cmdline is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // par2cmdline is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19
20 #include "par2cmdline.h"
21
22 #ifdef _MSC_VER
23 #ifdef _DEBUG
24 #undef THIS_FILE
25 static char THIS_FILE[]=__FILE__;
26 #define new DEBUG_NEW
27 #endif
28 #endif
29
30 // Construct the packet and store the filename and size.
31
Create(string filename,u64 filesize)32 bool DescriptionPacket::Create(string filename, u64 filesize)
33 {
34 // Allocate some extra bytes for the packet in memory so that strlen() can
35 // be used on the filename. The extra bytes do not get written to disk.
36 FILEDESCRIPTIONPACKET *packet = (FILEDESCRIPTIONPACKET *)AllocatePacket(sizeof(*packet) + (~3 & (3 + (u32)filename.size())), 4);
37
38 // Store everything that is currently known in the packet.
39
40 packet->header.magic = packet_magic;
41 packet->header.length = packetlength;
42 //packet->header.hash; // Not known yet
43 //packet->header.setid; // Not known yet
44 packet->header.type = filedescriptionpacket_type;
45
46 //packet->fileid; // Not known yet
47 //packet->hashfull; // Not known yet
48 //packet->hash16k; // Not known yet
49 packet->length = filesize;
50
51 memcpy(packet->name, filename.c_str(), filename.size());
52
53 return true;
54 }
55
56
Hash16k(const MD5Hash & hash)57 void DescriptionPacket::Hash16k(const MD5Hash &hash)
58 {
59 ((FILEDESCRIPTIONPACKET *)packetdata)->hash16k = hash;
60 }
61
HashFull(const MD5Hash & hash)62 void DescriptionPacket::HashFull(const MD5Hash &hash)
63 {
64 ((FILEDESCRIPTIONPACKET *)packetdata)->hashfull = hash;
65 }
66
ComputeFileId(void)67 void DescriptionPacket::ComputeFileId(void)
68 {
69 FILEDESCRIPTIONPACKET *packet = ((FILEDESCRIPTIONPACKET *)packetdata);
70
71 // Compute the fileid from the hash, length, and name fields in the packet.
72
73 MD5Context context;
74 context.Update(&packet->hash16k,
75 sizeof(FILEDESCRIPTIONPACKET)-offsetof(FILEDESCRIPTIONPACKET,hash16k)
76 +strlen((const char*)packet->name));
77 context.Final(packet->fileid);
78 }
79
80 // Load a description packet from a specified file
Load(DiskFile * diskfile,u64 offset,PACKET_HEADER & header)81 bool DescriptionPacket::Load(DiskFile *diskfile, u64 offset, PACKET_HEADER &header)
82 {
83 // Is the packet big enough
84 if (header.length <= sizeof(FILEDESCRIPTIONPACKET))
85 {
86 return false;
87 }
88
89 // Is the packet too large (what is the longest permissible filename)
90 if (header.length - sizeof(FILEDESCRIPTIONPACKET) > 100000)
91 {
92 return false;
93 }
94
95 // Allocate the packet (with a little extra so we will have NULLs after the filename)
96 FILEDESCRIPTIONPACKET *packet = (FILEDESCRIPTIONPACKET *)AllocatePacket((size_t)header.length, 4);
97
98 packet->header = header;
99
100 // Read the rest of the packet from disk
101 if (!diskfile->Read(offset + sizeof(PACKET_HEADER),
102 &packet->fileid,
103 (size_t)packet->header.length - sizeof(PACKET_HEADER)))
104 return false;
105
106 // Are the file and 16k hashes consistent
107 if (packet->length <= 16384 && packet->hash16k != packet->hashfull)
108 {
109 return false;
110 }
111
112 return true;
113 }
114