]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug 3053: cache version 1 LFS support detection broken
authorAmos Jeffries <squid3@treenet.co.nz>
Sun, 19 Sep 2010 22:56:59 +0000 (10:56 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Sun, 19 Sep 2010 22:56:59 +0000 (10:56 +1200)
Alter the upgrade detection to only be used if needed, and to load the
correct on-disk sizes for the fields being converted.

Lock the sfileno type down to 32-bits.

This also adds two new upgrade parsers:
 Fix 64-bit builds previously using sfileno as full 64-bit int
 Migrates swap.state from 32-bit to 64-bit time_t (old squid 2.4/2.5)
 64-bit->32-bit system time_t migration remains broken.

Per-file meta data is not altered by these changes, so problems may
remain there.

src/fs/ufs/ufscommon.cc
src/typedefs.h

index 2723e0744468fc0c3e762feb50cca213fef6da7a..fcfbab3d7a4db84c5d6a445afebcbe38d96ed256 100644 (file)
 
 CBDATA_CLASS_INIT(RebuildState);
 
-
-class UFSSwapLogParser_old:public UFSSwapLogParser
+/// Parse a swap header entry created on a system with 32-bit size_t and sfileno
+/// this is typical of 32-bit systems without large file support
+/// NP: SQUID_MD5_DIGEST_LENGTH is very risky still.
+class UFSSwapLogParser_v1_32bs:public UFSSwapLogParser
 {
 public:
+    /// version 1 cache swap.state entry with 32-bit size_t (swap_file_sz)
+    /// time_t an sfileno have no variation from the v1 baseline format
     struct StoreSwapLogDataOld {
         char op;
         sfileno swap_filen;
@@ -58,41 +62,134 @@ public:
         time_t lastref;
         time_t expires;
         time_t lastmod;
-        size_t swap_file_sz;
+        uint32_t swap_file_sz;
         u_short refcount;
         u_short flags;
         unsigned char key[SQUID_MD5_DIGEST_LENGTH];
     };
-    UFSSwapLogParser_old(FILE *fp):UFSSwapLogParser(fp) {
-        record_size = sizeof(UFSSwapLogParser_old::StoreSwapLogDataOld);
+    UFSSwapLogParser_v1_32bs(FILE *fp):UFSSwapLogParser(fp) {
+        record_size = sizeof(UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld);
     }
-    bool ReadRecord(StoreSwapLogData &swapData);
-};
+    /// Convert the on-disk 32-bit format to our current format while reading
+    bool ReadRecord(StoreSwapLogData &swapData) {
+        UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld readData;
+        int bytes = sizeof(UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld);
+
+        assert(log);
 
+        if (fread(&readData, bytes, 1, log) != 1) {
+            return false;
+        }
+        swapData.op = readData.op;
+        swapData.swap_filen = readData.swap_filen;
+        swapData.timestamp = readData.timestamp;
+        swapData.lastref = readData.lastref;
+        swapData.expires = readData.expires;
+        swapData.lastmod = readData.lastmod;
+        swapData.swap_file_sz = readData.swap_file_sz;
+        swapData.refcount = readData.refcount;
+        swapData.flags = readData.flags;
+        xmemcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH);
+        return true;
+    }
+};
 
-bool UFSSwapLogParser_old::ReadRecord(StoreSwapLogData &swapData)
+/// Parse a swap header entry created on a system with 32-bit size_t, time_t and sfileno
+/// this is typical of 32-bit systems without large file support and with old kernels
+/// NP: SQUID_MD5_DIGEST_LENGTH is very risky still.
+class UFSSwapLogParser_v1_32bst:public UFSSwapLogParser
 {
-    UFSSwapLogParser_old::StoreSwapLogDataOld readData;
-    int bytes = sizeof(UFSSwapLogParser_old::StoreSwapLogDataOld);
+public:
+    /// version 1 cache swap.state entry with 32-bit size_t (swap_file_sz)
+    /// time_t also differs
+    /// sfileno has no variation from the v1 baseline format
+    struct StoreSwapLogDataOld {
+        char op;
+        sfileno swap_filen;
+        int32_t timestamp;
+        int32_t lastref;
+        int32_t expires;
+        int32_t lastmod;
+        uint32_t swap_file_sz;
+        u_short refcount;
+        u_short flags;
+        unsigned char key[SQUID_MD5_DIGEST_LENGTH];
+    };
+    UFSSwapLogParser_v1_32bst(FILE *fp):UFSSwapLogParser(fp) {
+        record_size = sizeof(UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld);
+    }
+    /// Convert the on-disk 32-bit format to our current format while reading
+    bool ReadRecord(StoreSwapLogData &swapData) {
+        UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld readData;
+        int bytes = sizeof(UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld);
 
-    assert(log);
+        assert(log);
 
-    if (fread(&readData, bytes, 1, log) != 1) {
-        return false;
+        if (fread(&readData, bytes, 1, log) != 1) {
+            return false;
+        }
+        swapData.op = readData.op;
+        swapData.swap_filen = readData.swap_filen;
+        swapData.timestamp = readData.timestamp;
+        swapData.lastref = readData.lastref;
+        swapData.expires = readData.expires;
+        swapData.lastmod = readData.lastmod;
+        swapData.swap_file_sz = readData.swap_file_sz;
+        swapData.refcount = readData.refcount;
+        swapData.flags = readData.flags;
+        xmemcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH);
+        return true;
     }
-    swapData.op = readData.op;
-    swapData.swap_filen = readData.swap_filen;
-    swapData.timestamp = readData.timestamp;
-    swapData.lastref = readData.lastref;
-    swapData.expires = readData.expires;
-    swapData.lastmod = readData.lastmod;
-    swapData.swap_file_sz = readData.swap_file_sz;
-    swapData.refcount = readData.refcount;
-    swapData.flags = readData.flags;
-    xmemcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH);
-    return true;
-}
+};
+
+/// Parse a swap header entry created on a system with 64-bit size_t and sfileno
+/// this is typical of 64-bit systems prior to this patch fixing sfileno to 32-bits
+/// NP: SQUID_MD5_DIGEST_LENGTH is very risky still.
+class UFSSwapLogParser_v1_64bfn:public UFSSwapLogParser
+{
+public:
+    /// version 1 cache swap.state entry with 64-bit sfileno
+    struct StoreSwapLogDataOld {
+        char op;
+        int64_t swap_filen;
+        time_t timestamp;
+        time_t lastref;
+        time_t expires;
+        time_t lastmod;
+        uint64_t swap_file_sz;
+        u_short refcount;
+        u_short flags;
+        unsigned char key[SQUID_MD5_DIGEST_LENGTH];
+    };
+    UFSSwapLogParser_v1_64bfn(FILE *fp):UFSSwapLogParser(fp) {
+        record_size = sizeof(UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld);
+    }
+    /// Convert the on-disk 64-bit format to our current format while reading
+    bool ReadRecord(StoreSwapLogData &swapData) {
+        UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld readData;
+        int bytes = sizeof(UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld);
 
+        assert(log);
+
+        if (fread(&readData, bytes, 1, log) != 1) {
+            return false;
+        }
+        swapData.op = readData.op;
+        if ((readData.swap_filen>>32) != 0) {
+            fatalf("File ID on record is greater than maximum cache file ID.");
+        }
+        swapData.swap_filen = (int32_t)readData.swap_filen;
+        swapData.timestamp = readData.timestamp;
+        swapData.lastref = readData.lastref;
+        swapData.expires = readData.expires;
+        swapData.lastmod = readData.lastmod;
+        swapData.swap_file_sz = readData.swap_file_sz;
+        swapData.refcount = readData.refcount;
+        swapData.flags = readData.flags;
+        xmemcpy(swapData.key, readData.key, SQUID_MD5_DIGEST_LENGTH);
+        return true;
+    }
+};
 
 class UFSSwapLogParser_v1:public UFSSwapLogParser
 {
@@ -127,29 +224,58 @@ UFSSwapLogParser *UFSSwapLogParser::GetUFSSwapLogParser(FILE *fp)
         return NULL;
 
     if (header.op != SWAP_LOG_VERSION) {
-        debugs(47, 1, "Old swap file detected... ");
+        debugs(47, 1, "Old swap file detected...");
         fseek(fp, 0, SEEK_SET);
-        return new UFSSwapLogParser_old(fp);
+        return new UFSSwapLogParser_v1_32bs(fp); // Um. 32-bits except time_t, and can't determine that.
     }
 
     if (header.version == 1) {
         if (fseek(fp, header.record_size, SEEK_SET) != 0)
             return NULL;
 
-        if (header.record_size == sizeof(struct UFSSwapLogParser_old::StoreSwapLogDataOld)) {
-            debugs(47, 1, "Version 1 of swap file without LFS support detected... ");
-            return new UFSSwapLogParser_old(fp);
-        }
-
+        // baseline
+        // 32-bit sfileno
+        // native time_t (hopefully 64-bit)
+        // 64-bit file size
         if (header.record_size == sizeof(StoreSwapLogData)) {
             debugs(47, 1, "Version 1 of swap file with LFS support detected... ");
             return new UFSSwapLogParser_v1(fp);
         }
 
-        debugs(47, 1, "The swap file has wrong format!... ");
+        // which means we have a 3-way grid of permutations to import (yuck!)
+        // 1) sfileno 32-bit / 64-bit  (64-bit was broken)
+        // 2) time_t 32-bit / 64-bit
+        // 3) size_t 32-bit / 64-bit  (32-bit was pre-LFS)
+
+        // 32-bit systems...
+        // only LFS (size_t) differs from baseline
+        if (header.record_size == sizeof(struct UFSSwapLogParser_v1_32bs::StoreSwapLogDataOld)) {
+            debugs(47, 1, "Version 1 (32-bit) swap file without LFS support detected... ");
+            return new UFSSwapLogParser_v1_32bs(fp);
+        }
+        // LFS (size_t) and timestamps (time_t) differs from baseline
+        if (header.record_size == sizeof(struct UFSSwapLogParser_v1_32bst::StoreSwapLogDataOld)) {
+            debugs(47, 1, "Version 1 (32-bit) swap file with short timestamps and without LFS support detected... ");
+            return new UFSSwapLogParser_v1_32bst(fp);
+        }
+        // No downgrade for 64-bit timestamps to 32-bit.
+
+        // 64-bit systems
+        // sfileno was 64-bit for a some builds
+        if (header.record_size == sizeof(struct UFSSwapLogParser_v1_64bfn::StoreSwapLogDataOld)) {
+            debugs(47, 1, "Version 1 (64-bit) swap file with broken sfileno detected... ");
+            return new UFSSwapLogParser_v1_64bfn(fp);
+        }
+        // NP: 64-bit system with 32-bit size_t/time_t are not handled.
+
+        debugs(47, 1, "WARNING: The swap file has wrong format!... ");
+        debugs(47, 1, "NOTE: Cannot safely downgrade caches to short (32-bit) timestamps.");
         return NULL;
     }
 
+    // XXX: version 2 of swapfile. This time use fixed-bit sizes for everything!!
+    // and preferrably write to disk in network-order bytes for the larger fields.
+
     return NULL;
 }
 
index 73034c75e7ed7cb6de8955f5eccd7a0a1deebdb1..b33594e4c7ea9fbffb8844a2ad8be136859bad03 100644 (file)
@@ -36,7 +36,7 @@
 #ifndef SQUID_TYPEDEFS_H
 #define SQUID_TYPEDEFS_H
 
-typedef signed int sfileno;
+typedef int32_t sfileno;
 typedef signed int sdirno;
 
 typedef struct {