]> git.ipfire.org Git - thirdparty/squid.git/blame - src/fs/ufs/UFSSwapLogParser.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / fs / ufs / UFSSwapLogParser.cc
CommitLineData
58373ff8 1/*
4ac4a490 2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
187642d0 3 *
bbc27441
AJ
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.
58373ff8
FC
7 */
8
9#include "squid.h"
582c2af2 10#include "Debug.h"
58373ff8
FC
11#include "md5.h"
12#include "StoreSwapLogData.h"
13#include "swap_log_op.h"
14#include "UFSSwapLogParser.h"
15
582c2af2
FC
16#if HAVE_SYS_STAT_H
17#include <sys/stat.h>
18#endif
19
58373ff8
FC
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.
23class UFSSwapLogParser_v1_32bs:public Fs::Ufs::UFSSwapLogParser
24{
25public:
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 {
29 char op;
30 sfileno swap_filen;
31 time_t timestamp;
32 time_t lastref;
33 time_t expires;
34 time_t lastmod;
35 uint32_t swap_file_sz;
36 uint16_t refcount;
37 uint16_t flags;
38 unsigned char key[SQUID_MD5_DIGEST_LENGTH];
39 };
40 UFSSwapLogParser_v1_32bs(FILE *fp):Fs::Ufs::UFSSwapLogParser(fp) {
41 record_size = sizeof(UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld);
42 }
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);
47
48 assert(log);
49
50 if (fread(&readData, bytes, 1, log) != 1) {
51 return false;
52 }
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);
63 return true;
64 }
65};
66
67/// swap.state v2 log parser
68class UFSSwapLogParser_v2: public Fs::Ufs::UFSSwapLogParser
69{
70public:
71 UFSSwapLogParser_v2(FILE *fp): Fs::Ufs::UFSSwapLogParser(fp) {
72 record_size = sizeof(StoreSwapLogData);
73 }
74 bool ReadRecord(StoreSwapLogData &swapData) {
75 assert(log);
76 return fread(&swapData, sizeof(StoreSwapLogData), 1, log) == 1;
77 }
78};
79
80Fs::Ufs::UFSSwapLogParser *
81Fs::Ufs::UFSSwapLogParser::GetUFSSwapLogParser(FILE *fp)
82{
83 StoreSwapLogHeader header;
84
85 assert(fp);
86
87 if (fread(&header, sizeof(StoreSwapLogHeader), 1, fp) != 1)
88 return NULL;
89
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.
94 }
95
96 debugs(47, 2, "Swap file version: " << header.version);
97
98 if (header.version == 1) {
99 if (fseek(fp, header.record_size, SEEK_SET) != 0)
100 return NULL;
101
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.");
105 return NULL;
106
107#if UNUSED_CODE
108 // baseline
109 // 32-bit sfileno
110 // native time_t (hopefully 64-bit)
111 // 64-bit file size
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);
115 }
116
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)
121
122 // 32-bit systems...
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);
127 }
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);
132 }
133 // No downgrade for 64-bit timestamps to 32-bit.
134
135 // 64-bit systems
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);
140 }
141 // NP: 64-bit system with 32-bit size_t/time_t are not handled.
142
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.");
145 return NULL;
146#endif
147 }
148
149 if (header.version >= 2) {
150 if (!header.sane()) {
151 debugs(47, DBG_IMPORTANT, "ERROR: Corrupted v" << header.version <<
152 " swap file header.");
153 return NULL;
154 }
155
156 if (fseek(fp, header.record_size, SEEK_SET) != 0)
157 return NULL;
158
159 if (header.version == 2)
160 return new UFSSwapLogParser_v2(fp);
161 }
162
163 // TODO: v3: write to disk in network-order bytes for the larger fields?
164
165 debugs(47, DBG_IMPORTANT, "Unknown swap file version: " << header.version);
166 return NULL;
167}
168
169int
170Fs::Ufs::UFSSwapLogParser::SwapLogEntries()
171{
172 struct stat sb;
173
174 if (log_entries >= 0)
175 return log_entries;
176
177 if (log && record_size && 0 == fstat(fileno(log), &sb)) {
178 log_entries = sb.st_size/record_size;
179 return log_entries;
180 }
181
182 return 0;
183}
f53969cc 184