2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
12 #include "StoreSwapLogData.h"
13 #include "swap_log_op.h"
14 #include "UFSSwapLogParser.h"
20 /// Parse a swap header entry created on a system with 32-bit size_t and sfileno
21 /// this is typical of 32-bit systems without large file support
22 /// NP: SQUID_MD5_DIGEST_LENGTH is very risky still.
23 class UFSSwapLogParser_v1_32bs
:public Fs::Ufs::UFSSwapLogParser
26 /// version 1 cache swap.state entry with 32-bit size_t (swap_file_sz)
27 /// time_t an sfileno have no variation from the v1 baseline format
28 struct StoreSwapLogDataOld
{
35 uint32_t swap_file_sz
;
38 unsigned char key
[SQUID_MD5_DIGEST_LENGTH
];
40 UFSSwapLogParser_v1_32bs(FILE *fp
):Fs::Ufs::UFSSwapLogParser(fp
) {
41 record_size
= sizeof(UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld
);
43 /// Convert the on-disk 32-bit format to our current format while reading
44 bool ReadRecord(StoreSwapLogData
&swapData
) {
45 UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld readData
;
46 int bytes
= sizeof(UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld
);
50 if (fread(&readData
, bytes
, 1, log
) != 1) {
53 swapData
.op
= readData
.op
;
54 swapData
.swap_filen
= readData
.swap_filen
;
55 swapData
.timestamp
= readData
.timestamp
;
56 swapData
.lastref
= readData
.lastref
;
57 swapData
.expires
= readData
.expires
;
58 swapData
.lastmod
= readData
.lastmod
;
59 swapData
.swap_file_sz
= readData
.swap_file_sz
;
60 swapData
.refcount
= readData
.refcount
;
61 swapData
.flags
= readData
.flags
;
62 memcpy(swapData
.key
, readData
.key
, SQUID_MD5_DIGEST_LENGTH
);
67 /// swap.state v2 log parser
68 class UFSSwapLogParser_v2
: public Fs::Ufs::UFSSwapLogParser
71 UFSSwapLogParser_v2(FILE *fp
): Fs::Ufs::UFSSwapLogParser(fp
) {
72 record_size
= sizeof(StoreSwapLogData
);
74 bool ReadRecord(StoreSwapLogData
&swapData
) {
76 return fread(&swapData
, sizeof(StoreSwapLogData
), 1, log
) == 1;
80 Fs::Ufs::UFSSwapLogParser
*
81 Fs::Ufs::UFSSwapLogParser::GetUFSSwapLogParser(FILE *fp
)
83 StoreSwapLogHeader header
;
87 if (fread(&header
, sizeof(StoreSwapLogHeader
), 1, fp
) != 1)
90 if (header
.op
!= SWAP_LOG_VERSION
) {
91 debugs(47, DBG_IMPORTANT
, "Old swap file detected...");
92 fseek(fp
, 0, SEEK_SET
);
93 return new UFSSwapLogParser_v1_32bs(fp
); // Um. 32-bits except time_t, and can't determine that.
96 debugs(47, 2, "Swap file version: " << header
.version
);
98 if (header
.version
== 1) {
99 if (fseek(fp
, header
.record_size
, SEEK_SET
) != 0)
102 debugs(47, DBG_IMPORTANT
, "Rejecting swap file v1 to avoid cache " <<
103 "index corruption. Forcing a full cache index rebuild. " <<
104 "See Squid bug #3441.");
110 // native time_t (hopefully 64-bit)
112 if (header
.record_size
== sizeof(StoreSwapLogData
)) {
113 debugs(47, DBG_IMPORTANT
, "Version 1 of swap file with LFS support detected... ");
114 return new UFSSwapLogParser_v1(fp
);
117 // which means we have a 3-way grid of permutations to import (yuck!)
118 // 1) sfileno 32-bit / 64-bit (64-bit was broken)
119 // 2) time_t 32-bit / 64-bit
120 // 3) size_t 32-bit / 64-bit (32-bit was pre-LFS)
123 // only LFS (size_t) differs from baseline
124 if (header
.record_size
== sizeof(struct UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld
)) {
125 debugs(47, DBG_IMPORTANT
, "Version 1 (32-bit) swap file without LFS support detected... ");
126 return new UFSSwapLogParser_v1_32bs(fp
);
128 // LFS (size_t) and timestamps (time_t) differs from baseline
129 if (header
.record_size
== sizeof(struct UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld
)) {
130 debugs(47, DBG_IMPORTANT
, "Version 1 (32-bit) swap file with short timestamps and without LFS support detected... ");
131 return new UFSSwapLogParser_v1_32bst(fp
);
133 // No downgrade for 64-bit timestamps to 32-bit.
136 // sfileno was 64-bit for a some builds
137 if (header
.record_size
== sizeof(struct UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld
)) {
138 debugs(47, DBG_IMPORTANT
, "Version 1 (64-bit) swap file with broken sfileno detected... ");
139 return new UFSSwapLogParser_v1_64bfn(fp
);
141 // NP: 64-bit system with 32-bit size_t/time_t are not handled.
143 debugs(47, DBG_IMPORTANT
, "WARNING: The swap file has wrong format!... ");
144 debugs(47, DBG_IMPORTANT
, "NOTE: Cannot safely downgrade caches to short (32-bit) timestamps.");
149 if (header
.version
>= 2) {
150 if (!header
.sane()) {
151 debugs(47, DBG_IMPORTANT
, "ERROR: Corrupted v" << header
.version
<<
152 " swap file header.");
156 if (fseek(fp
, header
.record_size
, SEEK_SET
) != 0)
159 if (header
.version
== 2)
160 return new UFSSwapLogParser_v2(fp
);
163 // TODO: v3: write to disk in network-order bytes for the larger fields?
165 debugs(47, DBG_IMPORTANT
, "Unknown swap file version: " << header
.version
);
170 Fs::Ufs::UFSSwapLogParser::SwapLogEntries()
174 if (log_entries
>= 0)
177 if (log
&& record_size
&& 0 == fstat(fileno(log
), &sb
)) {
178 log_entries
= sb
.st_size
/record_size
;