diff options
author | Koen Kooi <koen@openembedded.org> | 2009-01-08 15:15:51 +0100 |
---|---|---|
committer | Koen Kooi <koen@openembedded.org> | 2009-01-08 15:15:51 +0100 |
commit | c1d6da72de49968c5fdb0d117681d7b23667156b (patch) | |
tree | 475bf0ea31045e80a05369b3aea46cb941f3ae07 /packages | |
parent | 7009de96358579b65a2f0168ab5a864247d6304b (diff) | |
parent | 46e900cd3d6c461317051a579f1d5ae278c1dc1b (diff) |
Merge branch 'org.openembedded.dev' of git@git.openembedded.net:openembedded into org.openembedded.dev
Diffstat (limited to 'packages')
9 files changed, 6029 insertions, 1 deletions
diff --git a/packages/linux/linux-openmoko-2.6.28/0001-squashfs-with-lzma.patch b/packages/linux/linux-openmoko-2.6.28/0001-squashfs-with-lzma.patch new file mode 100644 index 0000000000..04d47fe16f --- /dev/null +++ b/packages/linux/linux-openmoko-2.6.28/0001-squashfs-with-lzma.patch @@ -0,0 +1,5342 @@ + +diff -urN linux-2.6.23/fs/squashfs/LzmaDecode.c linux-2.6.23.sqlzma-ng/fs/squashfs/LzmaDecode.c +--- linux-2.6.23/fs/squashfs/LzmaDecode.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/fs/squashfs/LzmaDecode.c 2007-11-13 19:45:12.000000000 -0500 +@@ -0,0 +1,584 @@ ++/*
++ LzmaDecode.c
++ LZMA Decoder (optimized for Speed version)
++
++ LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
++ http://www.7-zip.org/
++
++ LZMA SDK is licensed under two licenses:
++ 1) GNU Lesser General Public License (GNU LGPL)
++ 2) Common Public License (CPL)
++ It means that you can select one of these two licenses and
++ follow rules of that license.
++
++ SPECIAL EXCEPTION:
++ Igor Pavlov, as the author of this Code, expressly permits you to
++ statically or dynamically link your Code (or bind by name) to the
++ interfaces of this file without subjecting your linked Code to the
++ terms of the CPL or GNU LGPL. Any modifications or additions
++ to this file, however, are subject to the LGPL or CPL terms.
++*/
++
++#include "LzmaDecode.h"
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++
++#define RC_READ_BYTE (*Buffer++)
++
++#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
++ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
++
++#ifdef _LZMA_IN_CB
++
++#define RC_TEST { if (Buffer == BufferLim) \
++ { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
++ BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
++
++#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
++
++#else
++
++#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
++
++#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
++
++#endif
++
++#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
++
++#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
++#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
++#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
++
++#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
++ { UpdateBit0(p); mi <<= 1; A0; } else \
++ { UpdateBit1(p); mi = (mi + mi) + 1; A1; }
++
++#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)
++
++#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
++ { int i = numLevels; res = 1; \
++ do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
++ res -= (1 << numLevels); }
++
++
++#define kNumPosBitsMax 4
++#define kNumPosStatesMax (1 << kNumPosBitsMax)
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define LenChoice 0
++#define LenChoice2 (LenChoice + 1)
++#define LenLow (LenChoice2 + 1)
++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
++#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
++
++
++#define kNumStates 12
++#define kNumLitStates 7
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#define kNumPosSlotBits 6
++#define kNumLenToPosStates 4
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++
++#define kMatchMinLen 2
++
++#define IsMatch 0
++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
++#define IsRepG0 (IsRep + kNumStates)
++#define IsRepG1 (IsRepG0 + kNumStates)
++#define IsRepG2 (IsRepG1 + kNumStates)
++#define IsRep0Long (IsRepG2 + kNumStates)
++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
++#define LenCoder (Align + kAlignTableSize)
++#define RepLenCoder (LenCoder + kNumLenProbs)
++#define Literal (RepLenCoder + kNumLenProbs)
++
++#if Literal != LZMA_BASE_SIZE
++StopCompilingDueBUG
++#endif
++
++int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
++{
++ unsigned char prop0;
++ if (size < LZMA_PROPERTIES_SIZE)
++ return LZMA_RESULT_DATA_ERROR;
++ prop0 = propsData[0];
++ if (prop0 >= (9 * 5 * 5))
++ return LZMA_RESULT_DATA_ERROR;
++ {
++ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
++ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
++ propsRes->lc = prop0;
++ /*
++ unsigned char remainder = (unsigned char)(prop0 / 9);
++ propsRes->lc = prop0 % 9;
++ propsRes->pb = remainder / 5;
++ propsRes->lp = remainder % 5;
++ */
++ }
++
++ #ifdef _LZMA_OUT_READ
++ {
++ int i;
++ propsRes->DictionarySize = 0;
++ for (i = 0; i < 4; i++)
++ propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
++ if (propsRes->DictionarySize == 0)
++ propsRes->DictionarySize = 1;
++ }
++ #endif
++ return LZMA_RESULT_OK;
++}
++
++#define kLzmaStreamWasFinishedId (-1)
++
++int LzmaDecode(CLzmaDecoderState *vs,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *InCallback,
++ #else
++ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
++ #endif
++ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
++{
++ CProb *p = vs->Probs;
++ SizeT nowPos = 0;
++ Byte previousByte = 0;
++ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
++ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
++ int lc = vs->Properties.lc;
++
++ #ifdef _LZMA_OUT_READ
++
++ UInt32 Range = vs->Range;
++ UInt32 Code = vs->Code;
++ #ifdef _LZMA_IN_CB
++ const Byte *Buffer = vs->Buffer;
++ const Byte *BufferLim = vs->BufferLim;
++ #else
++ const Byte *Buffer = inStream;
++ const Byte *BufferLim = inStream + inSize;
++ #endif
++ int state = vs->State;
++ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
++ int len = vs->RemainLen;
++ UInt32 globalPos = vs->GlobalPos;
++ UInt32 distanceLimit = vs->DistanceLimit;
++
++ Byte *dictionary = vs->Dictionary;
++ UInt32 dictionarySize = vs->Properties.DictionarySize;
++ UInt32 dictionaryPos = vs->DictionaryPos;
++
++ Byte tempDictionary[4];
++
++ #ifndef _LZMA_IN_CB
++ *inSizeProcessed = 0;
++ #endif
++ *outSizeProcessed = 0;
++ if (len == kLzmaStreamWasFinishedId)
++ return LZMA_RESULT_OK;
++
++ if (dictionarySize == 0)
++ {
++ dictionary = tempDictionary;
++ dictionarySize = 1;
++ tempDictionary[0] = vs->TempDictionary[0];
++ }
++
++ if (len == kLzmaNeedInitId)
++ {
++ {
++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
++ UInt32 i;
++ for (i = 0; i < numProbs; i++)
++ p[i] = kBitModelTotal >> 1;
++ rep0 = rep1 = rep2 = rep3 = 1;
++ state = 0;
++ globalPos = 0;
++ distanceLimit = 0;
++ dictionaryPos = 0;
++ dictionary[dictionarySize - 1] = 0;
++ #ifdef _LZMA_IN_CB
++ RC_INIT;
++ #else
++ RC_INIT(inStream, inSize);
++ #endif
++ }
++ len = 0;
++ }
++ while(len != 0 && nowPos < outSize)
++ {
++ UInt32 pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ len--;
++ }
++ if (dictionaryPos == 0)
++ previousByte = dictionary[dictionarySize - 1];
++ else
++ previousByte = dictionary[dictionaryPos - 1];
++
++ #else /* if !_LZMA_OUT_READ */
++
++ int state = 0;
++ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
++ int len = 0;
++ const Byte *Buffer;
++ const Byte *BufferLim;
++ UInt32 Range;
++ UInt32 Code;
++
++ #ifndef _LZMA_IN_CB
++ *inSizeProcessed = 0;
++ #endif
++ *outSizeProcessed = 0;
++
++ {
++ UInt32 i;
++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
++ for (i = 0; i < numProbs; i++)
++ p[i] = kBitModelTotal >> 1;
++ }
++
++ #ifdef _LZMA_IN_CB
++ RC_INIT;
++ #else
++ RC_INIT(inStream, inSize);
++ #endif
++
++ #endif /* _LZMA_OUT_READ */
++
++ while(nowPos < outSize)
++ {
++ CProb *prob;
++ UInt32 bound;
++ int posState = (int)(
++ (nowPos
++ #ifdef _LZMA_OUT_READ
++ + globalPos
++ #endif
++ )
++ & posStateMask);
++
++ prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
++ IfBit0(prob)
++ {
++ int symbol = 1;
++ UpdateBit0(prob)
++ prob = p + Literal + (LZMA_LIT_SIZE *
++ (((
++ (nowPos
++ #ifdef _LZMA_OUT_READ
++ + globalPos
++ #endif
++ )
++ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
++
++ if (state >= kNumLitStates)
++ {
++ int matchByte;
++ #ifdef _LZMA_OUT_READ
++ UInt32 pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ matchByte = dictionary[pos];
++ #else
++ matchByte = outStream[nowPos - rep0];
++ #endif
++ do
++ {
++ int bit;
++ CProb *probLit;
++ matchByte <<= 1;
++ bit = (matchByte & 0x100);
++ probLit = prob + 0x100 + bit + symbol;
++ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
++ }
++ while (symbol < 0x100);
++ }
++ while (symbol < 0x100)
++ {
++ CProb *probLit = prob + symbol;
++ RC_GET_BIT(probLit, symbol)
++ }
++ previousByte = (Byte)symbol;
++
++ outStream[nowPos++] = previousByte;
++ #ifdef _LZMA_OUT_READ
++ if (distanceLimit < dictionarySize)
++ distanceLimit++;
++
++ dictionary[dictionaryPos] = previousByte;
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ #endif
++ if (state < 4) state = 0;
++ else if (state < 10) state -= 3;
++ else state -= 6;
++ }
++ else
++ {
++ UpdateBit1(prob);
++ prob = p + IsRep + state;
++ IfBit0(prob)
++ {
++ UpdateBit0(prob);
++ rep3 = rep2;
++ rep2 = rep1;
++ rep1 = rep0;
++ state = state < kNumLitStates ? 0 : 3;
++ prob = p + LenCoder;
++ }
++ else
++ {
++ UpdateBit1(prob);
++ prob = p + IsRepG0 + state;
++ IfBit0(prob)
++ {
++ UpdateBit0(prob);
++ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
++ IfBit0(prob)
++ {
++ #ifdef _LZMA_OUT_READ
++ UInt32 pos;
++ #endif
++ UpdateBit0(prob);
++
++ #ifdef _LZMA_OUT_READ
++ if (distanceLimit == 0)
++ #else
++ if (nowPos == 0)
++ #endif
++ return LZMA_RESULT_DATA_ERROR;
++
++ state = state < kNumLitStates ? 9 : 11;
++ #ifdef _LZMA_OUT_READ
++ pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ previousByte = dictionary[pos];
++ dictionary[dictionaryPos] = previousByte;
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ #else
++ previousByte = outStream[nowPos - rep0];
++ #endif
++ outStream[nowPos++] = previousByte;
++ #ifdef _LZMA_OUT_READ
++ if (distanceLimit < dictionarySize)
++ distanceLimit++;
++ #endif
++
++ continue;
++ }
++ else
++ {
++ UpdateBit1(prob);
++ }
++ }
++ else
++ {
++ UInt32 distance;
++ UpdateBit1(prob);
++ prob = p + IsRepG1 + state;
++ IfBit0(prob)
++ {
++ UpdateBit0(prob);
++ distance = rep1;
++ }
++ else
++ {
++ UpdateBit1(prob);
++ prob = p + IsRepG2 + state;
++ IfBit0(prob)
++ {
++ UpdateBit0(prob);
++ distance = rep2;
++ }
++ else
++ {
++ UpdateBit1(prob);
++ distance = rep3;
++ rep3 = rep2;
++ }
++ rep2 = rep1;
++ }
++ rep1 = rep0;
++ rep0 = distance;
++ }
++ state = state < kNumLitStates ? 8 : 11;
++ prob = p + RepLenCoder;
++ }
++ {
++ int numBits, offset;
++ CProb *probLen = prob + LenChoice;
++ IfBit0(probLen)
++ {
++ UpdateBit0(probLen);
++ probLen = prob + LenLow + (posState << kLenNumLowBits);
++ offset = 0;
++ numBits = kLenNumLowBits;
++ }
++ else
++ {
++ UpdateBit1(probLen);
++ probLen = prob + LenChoice2;
++ IfBit0(probLen)
++ {
++ UpdateBit0(probLen);
++ probLen = prob + LenMid + (posState << kLenNumMidBits);
++ offset = kLenNumLowSymbols;
++ numBits = kLenNumMidBits;
++ }
++ else
++ {
++ UpdateBit1(probLen);
++ probLen = prob + LenHigh;
++ offset = kLenNumLowSymbols + kLenNumMidSymbols;
++ numBits = kLenNumHighBits;
++ }
++ }
++ RangeDecoderBitTreeDecode(probLen, numBits, len);
++ len += offset;
++ }
++
++ if (state < 4)
++ {
++ int posSlot;
++ state += kNumLitStates;
++ prob = p + PosSlot +
++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
++ kNumPosSlotBits);
++ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
++ if (posSlot >= kStartPosModelIndex)
++ {
++ int numDirectBits = ((posSlot >> 1) - 1);
++ rep0 = (2 | ((UInt32)posSlot & 1));
++ if (posSlot < kEndPosModelIndex)
++ {
++ rep0 <<= numDirectBits;
++ prob = p + SpecPos + rep0 - posSlot - 1;
++ }
++ else
++ {
++ numDirectBits -= kNumAlignBits;
++ do
++ {
++ RC_NORMALIZE
++ Range >>= 1;
++ rep0 <<= 1;
++ if (Code >= Range)
++ {
++ Code -= Range;
++ rep0 |= 1;
++ }
++ }
++ while (--numDirectBits != 0);
++ prob = p + Align;
++ rep0 <<= kNumAlignBits;
++ numDirectBits = kNumAlignBits;
++ }
++ {
++ int i = 1;
++ int mi = 1;
++ do
++ {
++ CProb *prob3 = prob + mi;
++ RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
++ i <<= 1;
++ }
++ while(--numDirectBits != 0);
++ }
++ }
++ else
++ rep0 = posSlot;
++ if (++rep0 == (UInt32)(0))
++ {
++ /* it's for stream version */
++ len = kLzmaStreamWasFinishedId;
++ break;
++ }
++ }
++
++ len += kMatchMinLen;
++ #ifdef _LZMA_OUT_READ
++ if (rep0 > distanceLimit)
++ #else
++ if (rep0 > nowPos)
++ #endif
++ return LZMA_RESULT_DATA_ERROR;
++
++ #ifdef _LZMA_OUT_READ
++ if (dictionarySize - distanceLimit > (UInt32)len)
++ distanceLimit += len;
++ else
++ distanceLimit = dictionarySize;
++ #endif
++
++ do
++ {
++ #ifdef _LZMA_OUT_READ
++ UInt32 pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ previousByte = dictionary[pos];
++ dictionary[dictionaryPos] = previousByte;
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ #else
++ previousByte = outStream[nowPos - rep0];
++ #endif
++ len--;
++ outStream[nowPos++] = previousByte;
++ }
++ while(len != 0 && nowPos < outSize);
++ }
++ }
++ RC_NORMALIZE;
++
++ #ifdef _LZMA_OUT_READ
++ vs->Range = Range;
++ vs->Code = Code;
++ vs->DictionaryPos = dictionaryPos;
++ vs->GlobalPos = globalPos + (UInt32)nowPos;
++ vs->DistanceLimit = distanceLimit;
++ vs->Reps[0] = rep0;
++ vs->Reps[1] = rep1;
++ vs->Reps[2] = rep2;
++ vs->Reps[3] = rep3;
++ vs->State = state;
++ vs->RemainLen = len;
++ vs->TempDictionary[0] = tempDictionary[0];
++ #endif
++
++ #ifdef _LZMA_IN_CB
++ vs->Buffer = Buffer;
++ vs->BufferLim = BufferLim;
++ #else
++ *inSizeProcessed = (SizeT)(Buffer - inStream);
++ #endif
++ *outSizeProcessed = nowPos;
++ return LZMA_RESULT_OK;
++}
+diff -urN linux-2.6.23/fs/squashfs/LzmaDecode.h linux-2.6.23.sqlzma-ng/fs/squashfs/LzmaDecode.h +--- linux-2.6.23/fs/squashfs/LzmaDecode.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/fs/squashfs/LzmaDecode.h 2007-11-13 19:45:12.000000000 -0500 +@@ -0,0 +1,113 @@ ++/*
++ LzmaDecode.h
++ LZMA Decoder interface
++
++ LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
++ http://www.7-zip.org/
++
++ LZMA SDK is licensed under two licenses:
++ 1) GNU Lesser General Public License (GNU LGPL)
++ 2) Common Public License (CPL)
++ It means that you can select one of these two licenses and
++ follow rules of that license.
++
++ SPECIAL EXCEPTION:
++ Igor Pavlov, as the author of this code, expressly permits you to
++ statically or dynamically link your code (or bind by name) to the
++ interfaces of this file without subjecting your linked code to the
++ terms of the CPL or GNU LGPL. Any modifications or additions
++ to this file, however, are subject to the LGPL or CPL terms.
++*/
++
++#ifndef __LZMADECODE_H
++#define __LZMADECODE_H
++
++#include "LzmaTypes.h"
++
++/* #define _LZMA_IN_CB */
++/* Use callback for input data */
++
++/* #define _LZMA_OUT_READ */
++/* Use read function for output data */
++
++/* #define _LZMA_PROB32 */
++/* It can increase speed on some 32-bit CPUs,
++ but memory usage will be doubled in that case */
++
++/* #define _LZMA_LOC_OPT */
++/* Enable local speed optimizations inside code */
++
++#ifdef _LZMA_PROB32
++#define CProb UInt32
++#else
++#define CProb UInt16
++#endif
++
++#define LZMA_RESULT_OK 0
++#define LZMA_RESULT_DATA_ERROR 1
++
++#ifdef _LZMA_IN_CB
++typedef struct _ILzmaInCallback
++{
++ int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
++} ILzmaInCallback;
++#endif
++
++#define LZMA_BASE_SIZE 1846
++#define LZMA_LIT_SIZE 768
++
++#define LZMA_PROPERTIES_SIZE 5
++
++typedef struct _CLzmaProperties
++{
++ int lc;
++ int lp;
++ int pb;
++ #ifdef _LZMA_OUT_READ
++ UInt32 DictionarySize;
++ #endif
++}CLzmaProperties;
++
++int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
++
++#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
++
++#define kLzmaNeedInitId (-2)
++
++typedef struct _CLzmaDecoderState
++{
++ CLzmaProperties Properties;
++ CProb *Probs;
++
++ #ifdef _LZMA_IN_CB
++ const unsigned char *Buffer;
++ const unsigned char *BufferLim;
++ #endif
++
++ #ifdef _LZMA_OUT_READ
++ unsigned char *Dictionary;
++ UInt32 Range;
++ UInt32 Code;
++ UInt32 DictionaryPos;
++ UInt32 GlobalPos;
++ UInt32 DistanceLimit;
++ UInt32 Reps[4];
++ int State;
++ int RemainLen;
++ unsigned char TempDictionary[4];
++ #endif
++} CLzmaDecoderState;
++
++#ifdef _LZMA_OUT_READ
++#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
++#endif
++
++int LzmaDecode(CLzmaDecoderState *vs,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *inCallback,
++ #else
++ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
++ #endif
++ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
++
++#endif
+diff -urN linux-2.6.23/fs/squashfs/LzmaTypes.h linux-2.6.23.sqlzma-ng/fs/squashfs/LzmaTypes.h +--- linux-2.6.23/fs/squashfs/LzmaTypes.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/fs/squashfs/LzmaTypes.h 2007-11-13 19:47:32.000000000 -0500 +@@ -0,0 +1,45 @@ ++/*
++LzmaTypes.h
++
++Types for LZMA Decoder
++
++This file written and distributed to public domain by Igor Pavlov.
++This file is part of LZMA SDK 4.40 (2006-05-01)
++*/
++
++#ifndef __LZMATYPES_H
++#define __LZMATYPES_H
++
++#ifndef _7ZIP_BYTE_DEFINED
++#define _7ZIP_BYTE_DEFINED
++typedef unsigned char Byte;
++#endif
++
++#ifndef _7ZIP_UINT16_DEFINED
++#define _7ZIP_UINT16_DEFINED
++typedef unsigned short UInt16;
++#endif
++
++#ifndef _7ZIP_UINT32_DEFINED
++#define _7ZIP_UINT32_DEFINED
++#ifdef _LZMA_UINT32_IS_ULONG
++typedef unsigned long UInt32;
++#else
++typedef unsigned int UInt32;
++#endif
++#endif
++
++/* #define _LZMA_NO_SYSTEM_SIZE_T */
++/* You can use it, if you don't want <stddef.h> */
++
++#ifndef _7ZIP_SIZET_DEFINED
++#define _7ZIP_SIZET_DEFINED
++#ifdef _LZMA_NO_SYSTEM_SIZE_T
++typedef UInt32 SizeT;
++#else
++#include <stddef.h>
++typedef size_t SizeT;
++#endif
++#endif
++
++#endif
+diff -urN linux-2.6.23/fs/squashfs/Makefile linux-2.6.23.sqlzma-ng/fs/squashfs/Makefile +--- linux-2.6.23/fs/squashfs/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/fs/squashfs/Makefile 2007-11-13 19:52:56.000000000 -0500 +@@ -0,0 +1,10 @@ ++# ++# Makefile for the linux squashfs routines. ++# ++ ++ ++obj-$(CONFIG_SQUASHFS) += unlzma.o sqlzma.o squashfs.o ++unlzma-y += module.o ++sqlzma-y += uncomp.o ++squashfs-y += inode.o ++squashfs-y += squashfs2_0.o +diff -urN linux-2.6.23/fs/squashfs/inode.c linux-2.6.23.sqlzma-ng/fs/squashfs/inode.c +--- linux-2.6.23/fs/squashfs/inode.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/fs/squashfs/inode.c 2007-11-13 19:14:24.000000000 -0500 +@@ -0,0 +1,2312 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher <phillip@lougher.demon.co.uk> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * inode.c ++ */ ++ ++#include <linux/squashfs_fs.h> ++#include <linux/module.h> ++#include <linux/zlib.h> ++#include <linux/fs.h> ++#include <linux/squashfs_fs_sb.h> ++#include <linux/squashfs_fs_i.h> ++#include <linux/buffer_head.h> ++#include <linux/vfs.h> ++#include <linux/vmalloc.h> ++#include <linux/smp_lock.h> ++#include <linux/sched.h> ++#include <linux/exportfs.h> ++ ++#include "squashfs.h" ++#include "sqlzma.h" ++ ++#undef KeepPreemptive ++#if defined(CONFIG_PREEMPT) && !defined(UnsquashNoPreempt) ++#define KeepPreemptive ++#endif ++ ++struct sqlzma { ++#ifdef KeepPreemptive ++ struct mutex mtx; ++#endif ++ unsigned char read_data[SQUASHFS_FILE_MAX_SIZE]; ++ struct sqlzma_un un; ++}; ++static DEFINE_PER_CPU(struct sqlzma *, sqlzma); ++ ++#define dpri(fmt, args...) /* printk("%s:%d: " fmt, __func__, __LINE__, ##args) */ ++#define dpri_un(un) dpri("un{%d, {%d %p}, {%d %p}, {%d %p}}\n", \ ++ (un)->un_lzma, (un)->un_a[0].sz, (un)->un_a[0].buf, \ ++ (un)->un_a[1].sz, (un)->un_a[1].buf, \ ++ (un)->un_a[2].sz, (un)->un_a[2].buf) ++ ++static int squashfs_cached_blks; ++ ++static void vfs_read_inode(struct inode *i); ++static struct dentry *squashfs_get_parent(struct dentry *child); ++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode); ++static int squashfs_statfs(struct dentry *, struct kstatfs *); ++static int squashfs_symlink_readpage(struct file *file, struct page *page); ++static long long read_blocklist(struct inode *inode, int index, ++ int readahead_blks, char *block_list, ++ unsigned short **block_p, unsigned int *bsize); ++static int squashfs_readpage(struct file *file, struct page *page); ++static int squashfs_readdir(struct file *, void *, filldir_t); ++static struct dentry *squashfs_lookup(struct inode *, struct dentry *, ++ struct nameidata *); ++static int squashfs_remount(struct super_block *s, int *flags, char *data); ++static void squashfs_put_super(struct super_block *); ++static int squashfs_get_sb(struct file_system_type *,int, const char *, void *, ++ struct vfsmount *); ++static struct inode *squashfs_alloc_inode(struct super_block *sb); ++static void squashfs_destroy_inode(struct inode *inode); ++static int init_inodecache(void); ++static void destroy_inodecache(void); ++ ++static struct file_system_type squashfs_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "squashfs", ++ .get_sb = squashfs_get_sb, ++ .kill_sb = kill_block_super, ++ .fs_flags = FS_REQUIRES_DEV ++}; ++ ++static const unsigned char squashfs_filetype_table[] = { ++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK ++}; ++ ++static struct super_operations squashfs_super_ops = { ++ .alloc_inode = squashfs_alloc_inode, ++ .destroy_inode = squashfs_destroy_inode, ++ .statfs = squashfs_statfs, ++ .put_super = squashfs_put_super, ++ .remount_fs = squashfs_remount ++}; ++ ++static struct super_operations squashfs_export_super_ops = { ++ .alloc_inode = squashfs_alloc_inode, ++ .destroy_inode = squashfs_destroy_inode, ++ .statfs = squashfs_statfs, ++ .put_super = squashfs_put_super, ++ .read_inode = vfs_read_inode ++}; ++ ++static struct export_operations squashfs_export_ops = { ++ .get_parent = squashfs_get_parent ++}; ++ ++SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = { ++ .readpage = squashfs_symlink_readpage ++}; ++ ++SQSH_EXTERN const struct address_space_operations squashfs_aops = { ++ .readpage = squashfs_readpage ++}; ++ ++static const struct file_operations squashfs_dir_ops = { ++ .read = generic_read_dir, ++ .readdir = squashfs_readdir ++}; ++ ++SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = { ++ .lookup = squashfs_lookup ++}; ++ ++ ++static struct buffer_head *get_block_length(struct super_block *s, ++ int *cur_index, int *offset, int *c_byte) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ unsigned short temp; ++ struct buffer_head *bh; ++ ++ if (!(bh = sb_bread(s, *cur_index))) ++ goto out; ++ ++ if (msblk->devblksize - *offset == 1) { ++ if (msblk->swap) ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ else ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ brelse(bh); ++ if (!(bh = sb_bread(s, ++(*cur_index)))) ++ goto out; ++ if (msblk->swap) ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ bh->b_data); ++ else ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ bh->b_data); ++ *c_byte = temp; ++ *offset = 1; ++ } else { ++ if (msblk->swap) { ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset + 1)); ++ } else { ++ ((unsigned char *) &temp)[0] = *((unsigned char *) ++ (bh->b_data + *offset)); ++ ((unsigned char *) &temp)[1] = *((unsigned char *) ++ (bh->b_data + *offset + 1)); ++ } ++ *c_byte = temp; ++ *offset += 2; ++ } ++ ++ if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) { ++ if (*offset == msblk->devblksize) { ++ brelse(bh); ++ if (!(bh = sb_bread(s, ++(*cur_index)))) ++ goto out; ++ *offset = 0; ++ } ++ if (*((unsigned char *) (bh->b_data + *offset)) != ++ SQUASHFS_MARKER_BYTE) { ++ ERROR("Metadata block marker corrupt @ %x\n", ++ *cur_index); ++ brelse(bh); ++ goto out; ++ } ++ (*offset)++; ++ } ++ return bh; ++ ++out: ++ return NULL; ++} ++ ++ ++SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, ++ long long index, unsigned int length, ++ long long *next_index, int srclength) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ struct buffer_head **bh; ++ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1); ++ unsigned int cur_index = index >> msblk->devblksize_log2; ++ int bytes, avail_bytes, b = 0, k = 0; ++ unsigned int compressed; ++ unsigned int c_byte = length; ++ ++ bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) * ++ sizeof(struct buffer_head *), GFP_KERNEL); ++ if (bh == NULL) ++ goto read_failure; ++ ++ if (c_byte) { ++ bytes = msblk->devblksize - offset; ++ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte); ++ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); ++ ++ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, ++ compressed ? "" : "un", (unsigned int) c_byte, srclength); ++ ++ if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used) ++ goto read_failure; ++ ++ bh[0] = sb_getblk(s, cur_index); ++ if (bh[0] == NULL) ++ goto block_release; ++ ++ for (b = 1; bytes < c_byte; b++) { ++ bh[b] = sb_getblk(s, ++cur_index); ++ if (bh[b] == NULL) ++ goto block_release; ++ bytes += msblk->devblksize; ++ } ++ ll_rw_block(READ, b, bh); ++ } else { ++ if (index < 0 || (index + 2) > sblk->bytes_used) ++ goto read_failure; ++ ++ bh[0] = get_block_length(s, (int *)&cur_index, (int *)&offset, ++ (int *)&c_byte); ++ if (bh[0] == NULL) ++ goto read_failure; ++ ++ bytes = msblk->devblksize - offset; ++ compressed = SQUASHFS_COMPRESSED(c_byte); ++ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); ++ ++ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed ++ ? "" : "un", (unsigned int) c_byte); ++ ++ if (c_byte > srclength || (index + c_byte) > sblk->bytes_used) ++ goto read_failure; ++ ++ for (b = 1; bytes < c_byte; b++) { ++ bh[b] = sb_getblk(s, ++cur_index); ++ if (bh[b] == NULL) ++ goto block_release; ++ bytes += msblk->devblksize; ++ } ++ ll_rw_block(READ, b - 1, bh + 1); ++ } ++ ++ if (compressed) { ++ int zlib_err = Z_STREAM_END; ++ int rest, start; ++ enum {Src, Dst}; ++ struct sized_buf sbuf[2]; ++ struct sqlzma *percpu; ++ ++ /* ++ * uncompress block ++ */ ++ ++ for (k = 0; k < b; k++) { ++ wait_on_buffer(bh[k]); ++ if (!buffer_uptodate(bh[k])) ++ goto block_release; ++ } ++ ++ avail_bytes = 0; ++ for (k = 0; !avail_bytes && k < b; k++) { ++ avail_bytes = msblk->devblksize - offset; ++ if (c_byte < avail_bytes) ++ avail_bytes = c_byte; ++ if (avail_bytes) ++ break; ++ offset = 0; ++ brelse(bh[k]); ++ } ++ bytes = 0; ++ if (!avail_bytes) ++ goto block_release; // nothing to be process ++ ++ start = k; ++ /* it disables preemption */ ++ percpu = get_cpu_var(sqlzma); ++#ifdef KeepPreemptive ++ put_cpu_var(sqlzma); ++ mutex_lock(&percpu->mtx); ++#endif ++ ++ for (; k < b; k++) { ++ memcpy(percpu->read_data + bytes, bh[k]->b_data + offset, ++ avail_bytes); ++ bytes += avail_bytes; ++ offset = 0; ++ brelse(bh[k]); ++ avail_bytes = msblk->devblksize - offset; ++ rest = c_byte - bytes; ++ if (rest < avail_bytes) ++ avail_bytes = rest; ++ } ++ ++ sbuf[Src].buf = percpu->read_data; ++ sbuf[Src].sz = bytes; ++ sbuf[Dst].buf = buffer; ++ sbuf[Dst].sz = srclength; ++ dpri_un(&percpu->un); ++ dpri("src %d %p, dst %d %p\n", sbuf[Src].sz, sbuf[Src].buf, ++ sbuf[Dst].sz, sbuf[Dst].buf); ++ zlib_err = sqlzma_un(&percpu->un, sbuf + Src, sbuf + Dst); ++ bytes = percpu->un.un_reslen; ++ ++#ifdef KeepPreemptive ++ mutex_unlock(&percpu->mtx); ++#else ++ put_cpu_var(sqlzma); ++#endif ++ if (unlikely(zlib_err)) { ++ dpri("zlib_err %d\n", zlib_err); ++ goto release_mutex; ++ } ++ } else { ++ int i; ++ ++ for(i = 0; i < b; i++) { ++ wait_on_buffer(bh[i]); ++ if (!buffer_uptodate(bh[i])) ++ goto block_release; ++ } ++ ++ for (bytes = 0; k < b; k++) { ++ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset); ++ ++ memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes); ++ bytes += avail_bytes; ++ offset = 0; ++ brelse(bh[k]); ++ } ++ } ++ ++ if (next_index) ++ *next_index = index + c_byte + (length ? 0 : ++ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2)); ++ ++ kfree(bh); ++ return bytes; ++ ++release_mutex: ++ //mutex_unlock(&msblk->read_data_mutex); ++ ++block_release: ++ for (; k < b; k++) ++ brelse(bh[k]); ++ ++read_failure: ++ ERROR("sb_bread failed reading block 0x%x\n", cur_index); ++ kfree(bh); ++ return 0; ++} ++ ++ ++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, void *buffer, ++ long long block, unsigned int offset, ++ int length, long long *next_block, ++ unsigned int *next_offset) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ int n, i, bytes, return_length = length; ++ long long next_index; ++ ++ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset); ++ ++ while (1) { ++ for (i = 0; i < squashfs_cached_blks; i++) ++ if (msblk->block_cache[i].block == block) ++ break; ++ ++ mutex_lock(&msblk->block_cache_mutex); ++ ++ if (i == squashfs_cached_blks) { ++ /* read inode header block */ ++ if (msblk->unused_cache_blks == 0) { ++ mutex_unlock(&msblk->block_cache_mutex); ++ wait_event(msblk->waitq, msblk->unused_cache_blks); ++ continue; ++ } ++ ++ i = msblk->next_cache; ++ for (n = 0; n < squashfs_cached_blks; n++) { ++ if (msblk->block_cache[i].block != SQUASHFS_USED_BLK) ++ break; ++ i = (i + 1) % squashfs_cached_blks; ++ } ++ ++ msblk->next_cache = (i + 1) % squashfs_cached_blks; ++ ++ if (msblk->block_cache[i].block == SQUASHFS_INVALID_BLK) { ++ msblk->block_cache[i].data = vmalloc(SQUASHFS_METADATA_SIZE); ++ if (msblk->block_cache[i].data == NULL) { ++ ERROR("Failed to allocate cache block\n"); ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto out; ++ } ++ } ++ ++ msblk->block_cache[i].block = SQUASHFS_USED_BLK; ++ msblk->unused_cache_blks --; ++ mutex_unlock(&msblk->block_cache_mutex); ++ ++ msblk->block_cache[i].length = squashfs_read_data(s, ++ msblk->block_cache[i].data, block, 0, &next_index, ++ SQUASHFS_METADATA_SIZE); ++ ++ if (msblk->block_cache[i].length == 0) { ++ ERROR("Unable to read cache block [%llx:%x]\n", block, offset); ++ mutex_lock(&msblk->block_cache_mutex); ++ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; ++ msblk->unused_cache_blks ++; ++ smp_mb(); ++ vfree(msblk->block_cache[i].data); ++ wake_up(&msblk->waitq); ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto out; ++ } ++ ++ mutex_lock(&msblk->block_cache_mutex); ++ msblk->block_cache[i].block = block; ++ msblk->block_cache[i].next_index = next_index; ++ msblk->unused_cache_blks ++; ++ smp_mb(); ++ wake_up(&msblk->waitq); ++ TRACE("Read cache block [%llx:%x]\n", block, offset); ++ } ++ ++ if (msblk->block_cache[i].block != block) { ++ mutex_unlock(&msblk->block_cache_mutex); ++ continue; ++ } ++ ++ bytes = msblk->block_cache[i].length - offset; ++ ++ if (bytes < 1) { ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto out; ++ } else if (bytes >= length) { ++ if (buffer) ++ memcpy(buffer, msblk->block_cache[i].data + offset, length); ++ if (msblk->block_cache[i].length - offset == length) { ++ *next_block = msblk->block_cache[i].next_index; ++ *next_offset = 0; ++ } else { ++ *next_block = block; ++ *next_offset = offset + length; ++ } ++ mutex_unlock(&msblk->block_cache_mutex); ++ goto finish; ++ } else { ++ if (buffer) { ++ memcpy(buffer, msblk->block_cache[i].data + offset, bytes); ++ buffer = (char *) buffer + bytes; ++ } ++ block = msblk->block_cache[i].next_index; ++ mutex_unlock(&msblk->block_cache_mutex); ++ length -= bytes; ++ offset = 0; ++ } ++ } ++ ++finish: ++ return return_length; ++out: ++ return 0; ++} ++ ++ ++static int get_fragment_location(struct super_block *s, unsigned int fragment, ++ long long *fragment_start_block, ++ unsigned int *fragment_size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start_block = ++ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); ++ struct squashfs_fragment_entry fragment_entry; ++ ++ if (msblk->swap) { ++ struct squashfs_fragment_entry sfragment_entry; ++ ++ if (!squashfs_get_cached_block(s, &sfragment_entry, start_block, offset, ++ sizeof(sfragment_entry), &start_block, ++ (unsigned int *)&offset)) ++ goto out; ++ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); ++ } else ++ if (!squashfs_get_cached_block(s, &fragment_entry, start_block, offset, ++ sizeof(fragment_entry), &start_block, ++ (unsigned int *)&offset)) ++ goto out; ++ ++ *fragment_start_block = fragment_entry.start_block; ++ *fragment_size = fragment_entry.size; ++ ++ return 1; ++ ++out: ++ return 0; ++} ++ ++ ++SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, ++ struct squashfs_fragment_cache *fragment) ++{ ++ mutex_lock(&msblk->fragment_mutex); ++ fragment->locked --; ++ if (fragment->locked == 0) { ++ msblk->unused_frag_blks ++; ++ smp_mb(); ++ wake_up(&msblk->fragment_wait_queue); ++ } ++ mutex_unlock(&msblk->fragment_mutex); ++} ++ ++ ++SQSH_EXTERN ++struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, ++ long long start_block, int length) ++{ ++ int i, n; ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ while (1) { ++ mutex_lock(&msblk->fragment_mutex); ++ ++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS && ++ msblk->fragment[i].block != start_block; i++); ++ ++ if (i == SQUASHFS_CACHED_FRAGMENTS) { ++ if (msblk->unused_frag_blks == 0) { ++ mutex_unlock(&msblk->fragment_mutex); ++ wait_event(msblk->fragment_wait_queue, msblk->unused_frag_blks); ++ continue; ++ } ++ ++ i = msblk->next_fragment; ++ for (n = 0; n < SQUASHFS_CACHED_FRAGMENTS; n++) { ++ if (msblk->fragment[i].locked == 0) ++ break; ++ i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS; ++ } ++ ++ msblk->next_fragment = (msblk->next_fragment + 1) % ++ SQUASHFS_CACHED_FRAGMENTS; ++ ++ if (msblk->fragment[i].data == NULL) { ++ msblk->fragment[i].data = vmalloc(sblk->block_size); ++ if (msblk->fragment[i].data == NULL) { ++ ERROR("Failed to allocate fragment cache block\n"); ++ mutex_unlock(&msblk->fragment_mutex); ++ goto out; ++ } ++ } ++ ++ msblk->unused_frag_blks --; ++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK; ++ msblk->fragment[i].locked = 1; ++ mutex_unlock(&msblk->fragment_mutex); ++ ++ msblk->fragment[i].length = squashfs_read_data(s, ++ msblk->fragment[i].data, start_block, length, NULL, ++ sblk->block_size); ++ ++ if (msblk->fragment[i].length == 0) { ++ ERROR("Unable to read fragment cache block [%llx]\n", start_block); ++ msblk->fragment[i].locked = 0; ++ msblk->unused_frag_blks ++; ++ smp_mb(); ++ wake_up(&msblk->fragment_wait_queue); ++ goto out; ++ } ++ ++ mutex_lock(&msblk->fragment_mutex); ++ msblk->fragment[i].block = start_block; ++ TRACE("New fragment %d, start block %lld, locked %d\n", ++ i, msblk->fragment[i].block, msblk->fragment[i].locked); ++ mutex_unlock(&msblk->fragment_mutex); ++ break; ++ } ++ ++ if (msblk->fragment[i].locked == 0) ++ msblk->unused_frag_blks --; ++ msblk->fragment[i].locked++; ++ mutex_unlock(&msblk->fragment_mutex); ++ TRACE("Got fragment %d, start block %lld, locked %d\n", i, ++ msblk->fragment[i].block, msblk->fragment[i].locked); ++ break; ++ } ++ ++ return &msblk->fragment[i]; ++ ++out: ++ return NULL; ++} ++ ++ ++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, ++ struct squashfs_base_inode_header *inodeb) ++{ ++ i->i_ino = inodeb->inode_number; ++ i->i_mtime.tv_sec = inodeb->mtime; ++ i->i_atime.tv_sec = inodeb->mtime; ++ i->i_ctime.tv_sec = inodeb->mtime; ++ i->i_uid = msblk->uid[inodeb->uid]; ++ i->i_mode = inodeb->mode; ++ i->i_size = 0; ++ ++ if (inodeb->guid == SQUASHFS_GUIDS) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msblk->guid[inodeb->guid]; ++} ++ ++ ++static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)]; ++ int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1); ++ squashfs_inode_t inode; ++ ++ TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino); ++ ++ if (msblk->swap) { ++ squashfs_inode_t sinode; ++ ++ if (!squashfs_get_cached_block(s, &sinode, start, offset, ++ sizeof(sinode), &start, (unsigned int *)&offset)) ++ goto out; ++ SQUASHFS_SWAP_INODE_T((&inode), &sinode); ++ } else if (!squashfs_get_cached_block(s, &inode, start, offset, ++ sizeof(inode), &start, (unsigned int *)&offset)) ++ goto out; ++ ++ TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode); ++ ++ return inode; ++ ++out: ++ return SQUASHFS_INVALID_BLK; ++} ++ ++ ++static void vfs_read_inode(struct inode *i) ++{ ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ squashfs_inode_t inode = squashfs_inode_lookup(i->i_sb, i->i_ino); ++ ++ TRACE("Entered vfs_read_inode\n"); ++ ++ if(inode != SQUASHFS_INVALID_BLK) ++ (msblk->read_inode)(i, inode); ++} ++ ++ ++static struct dentry *squashfs_get_parent(struct dentry *child) ++{ ++ struct inode *i = child->d_inode; ++ struct inode *parent = iget(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode); ++ struct dentry *rv; ++ ++ TRACE("Entered squashfs_get_parent\n"); ++ ++ if(parent == NULL) { ++ rv = ERR_PTR(-EACCES); ++ goto out; ++ } ++ ++ rv = d_alloc_anon(parent); ++ if(rv == NULL) ++ rv = ERR_PTR(-ENOMEM); ++ ++out: ++ return rv; ++} ++ ++ ++SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s, ++ squashfs_inode_t inode, unsigned int inode_number) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct inode *i = iget_locked(s, inode_number); ++ ++ TRACE("Entered squashfs_iget\n"); ++ ++ if(i && (i->i_state & I_NEW)) { ++ (msblk->read_inode)(i, inode); ++ unlock_new_inode(i); ++ } ++ ++ return i; ++} ++ ++ ++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode) ++{ ++ struct super_block *s = i->i_sb; ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start; ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); ++ long long next_block; ++ unsigned int next_offset; ++ union squashfs_inode_header id, sid; ++ struct squashfs_base_inode_header *inodeb = &id.base, *sinodeb = &sid.base; ++ ++ TRACE("Entered squashfs_read_inode\n"); ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodeb, block, offset, ++ sizeof(*sinodeb), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, sizeof(*sinodeb)); ++ } else ++ if (!squashfs_get_cached_block(s, inodeb, block, offset, ++ sizeof(*inodeb), &next_block, &next_offset)) ++ goto failed_read; ++ ++ squashfs_new_inode(msblk, i, inodeb); ++ ++ switch(inodeb->inode_type) { ++ case SQUASHFS_FILE_TYPE: { ++ unsigned int frag_size; ++ long long frag_blk; ++ struct squashfs_reg_inode_header *inodep = &id.reg; ++ struct squashfs_reg_inode_header *sinodep = &sid.reg; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG) ++ if(!get_fragment_location(s, inodep->fragment, &frag_blk, ++ &frag_size)) ++ goto failed_read; ++ ++ i->i_nlink = 1; ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ i->i_data.a_ops = &squashfs_aops; ++ ++ TRACE("File inode %x:%x, start_block %llx, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_LREG_TYPE: { ++ unsigned int frag_size; ++ long long frag_blk; ++ struct squashfs_lreg_inode_header *inodep = &id.lreg; ++ struct squashfs_lreg_inode_header *sinodep = &sid.lreg; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG) ++ if (!get_fragment_location(s, inodep->fragment, &frag_blk, ++ &frag_size)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ i->i_data.a_ops = &squashfs_aops; ++ ++ TRACE("File inode %x:%x, start_block %llx, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ struct squashfs_dir_inode_header *inodep = &id.dir; ++ struct squashfs_dir_inode_header *sinodep = &sid.dir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = 0; ++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; ++ ++ TRACE("Directory inode %x:%x, start_block %x, offset " ++ "%x\n", SQUASHFS_INODE_BLK(inode), ++ offset, inodep->start_block, ++ inodep->offset); ++ break; ++ } ++ case SQUASHFS_LDIR_TYPE: { ++ struct squashfs_ldir_inode_header *inodep = &id.ldir; ++ struct squashfs_ldir_inode_header *sinodep = &sid.ldir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops; ++ i->i_fop = &squashfs_dir_ops; ++ i->i_mode |= S_IFDIR; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block; ++ SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count; ++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; ++ ++ TRACE("Long directory inode %x:%x, start_block %x, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, inodep->offset); ++ break; ++ } ++ case SQUASHFS_SYMLINK_TYPE: { ++ struct squashfs_symlink_inode_header *inodep = &id.symlink; ++ struct squashfs_symlink_inode_header *sinodep = &sid.symlink; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_size = inodep->symlink_size; ++ i->i_op = &page_symlink_inode_operations; ++ i->i_data.a_ops = &squashfs_symlink_aops; ++ i->i_mode |= S_IFLNK; ++ SQUASHFS_I(i)->start_block = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ ++ TRACE("Symbolic link inode %x:%x, start_block %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ struct squashfs_dev_inode_header *inodep = &id.dev; ++ struct squashfs_dev_inode_header *sinodep = &sid.dev; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ? ++ S_IFCHR : S_IFBLK; ++ init_special_inode(i, i->i_mode, old_decode_dev(inodep->rdev)); ++ ++ TRACE("Device inode %x:%x, rdev %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, inodep->rdev); ++ break; ++ } ++ case SQUASHFS_FIFO_TYPE: ++ case SQUASHFS_SOCKET_TYPE: { ++ struct squashfs_ipc_inode_header *inodep = &id.ipc; ++ struct squashfs_ipc_inode_header *sinodep = &sid.ipc; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, sinodep, block, offset, ++ sizeof(*sinodep), &next_block, &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, inodep, block, offset, ++ sizeof(*inodep), &next_block, &next_offset)) ++ goto failed_read; ++ ++ i->i_nlink = inodep->nlink; ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ++ ? S_IFIFO : S_IFSOCK; ++ init_special_inode(i, i->i_mode, 0); ++ break; ++ } ++ default: ++ ERROR("Unknown inode type %d in squashfs_iget!\n", ++ inodeb->inode_type); ++ goto failed_read1; ++ } ++ ++ return 1; ++ ++failed_read: ++ ERROR("Unable to read inode [%llx:%x]\n", block, offset); ++ ++failed_read1: ++ make_bad_inode(i); ++ return 0; ++} ++ ++ ++static int read_inode_lookup_table(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes); ++ ++ TRACE("In read_inode_lookup_table, length %d\n", length); ++ ++ /* Allocate inode lookup table */ ++ msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL); ++ if (msblk->inode_lookup_table == NULL) { ++ ERROR("Failed to allocate inode lookup table\n"); ++ return 0; ++ } ++ ++ if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table, ++ sblk->lookup_table_start, length | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { ++ ERROR("unable to read inode lookup table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ long long block; ++ ++ for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) { ++ /* XXX */ ++ SQUASHFS_SWAP_LOOKUP_BLOCKS((&block), ++ &msblk->inode_lookup_table[i], 1); ++ msblk->inode_lookup_table[i] = block; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int read_fragment_index_table(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments); ++ ++ if(length == 0) ++ return 1; ++ ++ /* Allocate fragment index table */ ++ msblk->fragment_index = kmalloc(length, GFP_KERNEL); ++ if (msblk->fragment_index == NULL) { ++ ERROR("Failed to allocate fragment index table\n"); ++ return 0; ++ } ++ ++ if (!squashfs_read_data(s, (char *) msblk->fragment_index, ++ sblk->fragment_table_start, length | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { ++ ERROR("unable to read fragment index table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ long long fragment; ++ ++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) { ++ /* XXX */ ++ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), ++ &msblk->fragment_index[i], 1); ++ msblk->fragment_index[i] = fragment; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int readahead_metadata(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ int i; ++ ++ squashfs_cached_blks = SQUASHFS_CACHED_BLKS; ++ ++ /* Init inode_table block pointer array */ ++ msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) * ++ squashfs_cached_blks, GFP_KERNEL); ++ if (msblk->block_cache == NULL) { ++ ERROR("Failed to allocate block cache\n"); ++ goto failed; ++ } ++ ++ for (i = 0; i < squashfs_cached_blks; i++) ++ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; ++ ++ msblk->next_cache = 0; ++ msblk->unused_cache_blks = squashfs_cached_blks; ++ ++ return 1; ++ ++failed: ++ return 0; ++} ++ ++ ++static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ msblk->read_inode = squashfs_read_inode; ++ msblk->read_blocklist = read_blocklist; ++ msblk->read_fragment_index_table = read_fragment_index_table; ++ ++ if (sblk->s_major == 1) { ++ if (!squashfs_1_0_supported(msblk)) { ++ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems " ++ "are unsupported\n"); ++ SERROR("Please recompile with Squashfs 1.0 support enabled\n"); ++ return 0; ++ } ++ } else if (sblk->s_major == 2) { ++ if (!squashfs_2_0_supported(msblk)) { ++ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems " ++ "are unsupported\n"); ++ SERROR("Please recompile with Squashfs 2.0 support enabled\n"); ++ return 0; ++ } ++ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor > ++ SQUASHFS_MINOR) { ++ SERROR("Major/Minor mismatch, trying to mount newer %d.%d " ++ "filesystem\n", sblk->s_major, sblk->s_minor); ++ SERROR("Please update your kernel\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++static int squashfs_fill_super(struct super_block *s, void *data, int silent) ++{ ++ struct squashfs_sb_info *msblk; ++ struct squashfs_super_block *sblk; ++ int i, err; ++ char b[BDEVNAME_SIZE]; ++ struct inode *root; ++ ++ TRACE("Entered squashfs_fill_superblock\n"); ++ ++ err = -ENOMEM; ++ s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL); ++ if (s->s_fs_info == NULL) { ++ ERROR("Failed to allocate superblock\n"); ++ goto failure; ++ } ++ msblk = s->s_fs_info; ++ ++ sblk = &msblk->sblk; ++ ++ msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE); ++ msblk->devblksize_log2 = ffz(~msblk->devblksize); ++ ++ //mutex_init(&msblk->read_data_mutex); ++ mutex_init(&msblk->read_page_mutex); ++ mutex_init(&msblk->block_cache_mutex); ++ mutex_init(&msblk->fragment_mutex); ++ mutex_init(&msblk->meta_index_mutex); ++ ++ init_waitqueue_head(&msblk->waitq); ++ init_waitqueue_head(&msblk->fragment_wait_queue); ++ ++ /* sblk->bytes_used is checked in squashfs_read_data to ensure reads are not ++ * beyond filesystem end. As we're using squashfs_read_data to read sblk here, ++ * first set sblk->bytes_used to a useful value */ ++ err = -EINVAL; ++ sblk->bytes_used = sizeof(struct squashfs_super_block); ++ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, ++ sizeof(struct squashfs_super_block) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) { ++ SERROR("unable to read superblock\n"); ++ goto failed_mount; ++ } ++ ++ /* Check it is a SQUASHFS superblock */ ++ s->s_magic = sblk->s_magic; ++ msblk->swap = 0; ++ dpri("magic 0x%x\n", sblk->s_magic); ++ switch (sblk->s_magic) { ++ struct squashfs_super_block ssblk; ++ ++ case SQUASHFS_MAGIC_SWAP: ++ /*FALLTHROUGH*/ ++ case SQUASHFS_MAGIC_LZMA_SWAP: ++ WARNING("Mounting a different endian SQUASHFS " ++ "filesystem on %s\n", bdevname(s->s_bdev, b)); ++ ++ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk); ++ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block)); ++ msblk->swap = 1; ++ /*FALLTHROUGH*/ ++ case SQUASHFS_MAGIC: ++ case SQUASHFS_MAGIC_LZMA: ++ break; ++ default: ++ SERROR("Can't find a SQUASHFS superblock on %s\n", ++ bdevname(s->s_bdev, b)); ++ goto failed_mount; ++ } ++ ++ { ++ struct sqlzma *p; ++ dpri("block_size %d\n", sblk->block_size); ++ BUG_ON(sblk->block_size > sizeof(p->read_data)); ++ } ++ ++ /* Check the MAJOR & MINOR versions */ ++ if(!supported_squashfs_filesystem(msblk, silent)) ++ goto failed_mount; ++ ++ /* Check the filesystem does not extend beyond the end of the ++ block device */ ++ if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode)) ++ goto failed_mount; ++ ++ /* Check the root inode for sanity */ ++ if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE) ++ goto failed_mount; ++ ++ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); ++ TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sblk->flags) ++ ? "un" : ""); ++ TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sblk->flags) ++ ? "un" : ""); ++ TRACE("Check data is %spresent in the filesystem\n", ++ SQUASHFS_CHECK_DATA(sblk->flags) ? "" : "not "); ++ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used); ++ TRACE("Block size %d\n", sblk->block_size); ++ TRACE("Number of inodes %d\n", sblk->inodes); ++ if (sblk->s_major > 1) ++ TRACE("Number of fragments %d\n", sblk->fragments); ++ TRACE("Number of uids %d\n", sblk->no_uids); ++ TRACE("Number of gids %d\n", sblk->no_guids); ++ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start); ++ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start); ++ if (sblk->s_major > 1) ++ TRACE("sblk->fragment_table_start %llx\n", sblk->fragment_table_start); ++ TRACE("sblk->uid_start %llx\n", sblk->uid_start); ++ ++ s->s_maxbytes = MAX_LFS_FILESIZE; ++ s->s_flags |= MS_RDONLY; ++ s->s_op = &squashfs_super_ops; ++ ++ if (readahead_metadata(s) == 0) ++ goto failed_mount; ++ ++ /* Allocate read_page block */ ++ err = -ENOMEM; ++ msblk->read_page = vmalloc(sblk->block_size); ++ if (msblk->read_page == NULL) { ++ ERROR("Failed to allocate read_page block\n"); ++ goto failed_mount; ++ } ++ ++ /* Allocate uid and gid tables */ ++ msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int), GFP_KERNEL); ++ if (msblk->uid == NULL) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ goto failed_mount; ++ } ++ msblk->guid = msblk->uid + sblk->no_uids; ++ ++ dpri("swap %d\n", msblk->swap); ++ err = -EINVAL; ++ if (msblk->swap) { ++ unsigned int *suid; ++ ++ err = -ENOMEM; ++ suid = kmalloc(sizeof(*suid) * (sblk->no_uids + sblk->no_guids), ++ GFP_KERNEL); ++ if (unlikely(!suid)) ++ goto failed_mount; ++ ++ err = -EINVAL; ++ if (!squashfs_read_data(s, (char *)suid, sblk->uid_start, ++ ((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int)) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { ++ ERROR("unable to read uid/gid table\n"); ++ kfree(suid); ++ goto failed_mount; ++ } ++ ++ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids + ++ sblk->no_guids), (sizeof(unsigned int) * 8)); ++ kfree(suid); ++ } else ++ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start, ++ ((sblk->no_uids + sblk->no_guids) * ++ sizeof(unsigned int)) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) { ++ ERROR("unable to read uid/gid table\n"); ++ goto failed_mount; ++ } ++ ++ ++ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk)) ++ goto allocate_root; ++ ++ err = -ENOMEM; ++ msblk->fragment = kzalloc(sizeof(struct squashfs_fragment_cache) * ++ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL); ++ if (msblk->fragment == NULL) { ++ ERROR("Failed to allocate fragment block cache\n"); ++ goto failed_mount; ++ } ++ ++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { ++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK; ++ } ++ ++ msblk->next_fragment = 0; ++ msblk->unused_frag_blks = SQUASHFS_CACHED_FRAGMENTS; ++ ++ /* Allocate and read fragment index table */ ++ if (msblk->read_fragment_index_table(s) == 0) ++ goto failed_mount; ++ ++ if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK) ++ goto allocate_root; ++ ++ /* Allocate and read inode lookup table */ ++ if (read_inode_lookup_table(s) == 0) ++ goto failed_mount; ++ ++ s->s_op = &squashfs_export_super_ops; ++ s->s_export_op = &squashfs_export_ops; ++ ++allocate_root: ++ dpri("alloate_root\n"); ++ root = new_inode(s); ++ if ((msblk->read_inode)(root, sblk->root_inode) == 0) { ++ iput(root); ++ goto failed_mount; ++ } ++ insert_inode_hash(root); ++ ++ s->s_root = d_alloc_root(root); ++ if (s->s_root == NULL) { ++ ERROR("Root inode create failed\n"); ++ iput(root); ++ goto failed_mount; ++ } ++ ++ TRACE("Leaving squashfs_fill_super\n"); ++ return 0; ++ ++failed_mount: ++ kfree(msblk->inode_lookup_table); ++ kfree(msblk->fragment_index); ++ kfree(msblk->fragment); ++ kfree(msblk->uid); ++ vfree(msblk->read_page); ++ kfree(msblk->block_cache); ++ kfree(msblk->fragment_index_2); ++ kfree(s->s_fs_info); ++ s->s_fs_info = NULL; ++ failure: ++ return err; ++} ++ ++ ++static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ TRACE("Entered squashfs_statfs\n"); ++ ++ buf->f_type = sblk->s_magic; ++ buf->f_bsize = sblk->block_size; ++ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1; ++ buf->f_bfree = buf->f_bavail = 0; ++ buf->f_files = sblk->inodes; ++ buf->f_ffree = 0; ++ buf->f_namelen = SQUASHFS_NAME_LEN; ++ ++ return 0; ++} ++ ++ ++static int squashfs_symlink_readpage(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ int index = page->index << PAGE_CACHE_SHIFT, length, bytes, avail_bytes; ++ long long block = SQUASHFS_I(inode)->start_block; ++ int offset = SQUASHFS_I(inode)->offset; ++ void *pageaddr = kmap(page); ++ ++ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block " ++ "%llx, offset %x\n", page->index, ++ SQUASHFS_I(inode)->start_block, ++ SQUASHFS_I(inode)->offset); ++ ++ for (length = 0; length < index; length += bytes) { ++ bytes = squashfs_get_cached_block(inode->i_sb, NULL, block, ++ offset, PAGE_CACHE_SIZE, &block, ++ (unsigned int *)&offset); ++ if (bytes == 0) { ++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); ++ goto skip_read; ++ } ++ } ++ ++ if (length != index) { ++ ERROR("(squashfs_symlink_readpage) length != index\n"); ++ bytes = 0; ++ goto skip_read; ++ } ++ ++ avail_bytes = min_t(int, i_size_read(inode) - length, PAGE_CACHE_SIZE); ++ ++ bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset, ++ avail_bytes, &block, (unsigned int *)&offset); ++ if (bytes == 0) ++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); ++ ++skip_read: ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); ++ kunmap(page); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ return 0; ++} ++ ++ ++static struct meta_index *locate_meta_index(struct inode *inode, int index, int offset) ++{ ++ struct meta_index *meta = NULL; ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ int i; ++ ++ mutex_lock(&msblk->meta_index_mutex); ++ ++ TRACE("locate_meta_index: index %d, offset %d\n", index, offset); ++ ++ if (msblk->meta_index == NULL) ++ goto not_allocated; ++ ++ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) { ++ if (msblk->meta_index[i].inode_number == inode->i_ino && ++ msblk->meta_index[i].offset >= offset && ++ msblk->meta_index[i].offset <= index && ++ msblk->meta_index[i].locked == 0) { ++ TRACE("locate_meta_index: entry %d, offset %d\n", i, ++ msblk->meta_index[i].offset); ++ meta = &msblk->meta_index[i]; ++ offset = meta->offset; ++ } ++ } ++ ++ if (meta) ++ meta->locked = 1; ++ ++not_allocated: ++ mutex_unlock(&msblk->meta_index_mutex); ++ ++ return meta; ++} ++ ++ ++static struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip) ++{ ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct meta_index *meta = NULL; ++ int i; ++ ++ mutex_lock(&msblk->meta_index_mutex); ++ ++ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip); ++ ++ if (msblk->meta_index == NULL) { ++ msblk->meta_index = kmalloc(sizeof(struct meta_index) * ++ SQUASHFS_META_NUMBER, GFP_KERNEL); ++ if (msblk->meta_index == NULL) { ++ ERROR("Failed to allocate meta_index\n"); ++ goto failed; ++ } ++ for (i = 0; i < SQUASHFS_META_NUMBER; i++) { ++ msblk->meta_index[i].inode_number = 0; ++ msblk->meta_index[i].locked = 0; ++ } ++ msblk->next_meta_index = 0; ++ } ++ ++ for (i = SQUASHFS_META_NUMBER; i && ++ msblk->meta_index[msblk->next_meta_index].locked; i --) ++ msblk->next_meta_index = (msblk->next_meta_index + 1) % ++ SQUASHFS_META_NUMBER; ++ ++ if (i == 0) { ++ TRACE("empty_meta_index: failed!\n"); ++ goto failed; ++ } ++ ++ TRACE("empty_meta_index: returned meta entry %d, %p\n", ++ msblk->next_meta_index, ++ &msblk->meta_index[msblk->next_meta_index]); ++ ++ meta = &msblk->meta_index[msblk->next_meta_index]; ++ msblk->next_meta_index = (msblk->next_meta_index + 1) % ++ SQUASHFS_META_NUMBER; ++ ++ meta->inode_number = inode->i_ino; ++ meta->offset = offset; ++ meta->skip = skip; ++ meta->entries = 0; ++ meta->locked = 1; ++ ++failed: ++ mutex_unlock(&msblk->meta_index_mutex); ++ return meta; ++} ++ ++ ++static void release_meta_index(struct inode *inode, struct meta_index *meta) ++{ ++ meta->locked = 0; ++ smp_mb(); ++} ++ ++ ++static int read_block_index(struct super_block *s, int blocks, char *block_list, ++ long long *start_block, int *offset) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ unsigned int *block_listp; ++ int block = 0; ++ ++ if (msblk->swap) { ++ char *sblock_list; ++ ++ sblock_list = kmalloc(blocks << 2, GFP_KERNEL); ++ if (unlikely(!sblock_list)) ++ goto failure; ++ ++ if (!squashfs_get_cached_block(s, sblock_list, *start_block, ++ *offset, blocks << 2, start_block, (unsigned int *)offset)) { ++ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset); ++ kfree(sblock_list); ++ goto failure; ++ } ++ SQUASHFS_SWAP_INTS(((unsigned int *)block_list), ++ ((unsigned int *)sblock_list), blocks); ++ kfree(sblock_list); ++ } else { ++ if (!squashfs_get_cached_block(s, block_list, *start_block, ++ *offset, blocks << 2, start_block, (unsigned int *)offset)) { ++ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset); ++ goto failure; ++ } ++ } ++ ++ for (block_listp = (unsigned int *) block_list; blocks; ++ block_listp++, blocks --) ++ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); ++ ++ return block; ++ ++failure: ++ return -1; ++} ++ ++ ++#define SIZE 256 ++ ++static inline int calculate_skip(int blocks) { ++ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES); ++ return skip >= 7 ? 7 : skip + 1; ++} ++ ++ ++static int get_meta_index(struct inode *inode, int index, ++ long long *index_block, int *index_offset, ++ long long *data_block, char *block_list) ++{ ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log); ++ int offset = 0; ++ struct meta_index *meta; ++ struct meta_entry *meta_entry; ++ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start; ++ int cur_offset = SQUASHFS_I(inode)->offset; ++ long long cur_data_block = SQUASHFS_I(inode)->start_block; ++ int i; ++ ++ index /= SQUASHFS_META_INDEXES * skip; ++ ++ while (offset < index) { ++ meta = locate_meta_index(inode, index, offset + 1); ++ ++ if (meta == NULL) { ++ meta = empty_meta_index(inode, offset + 1, skip); ++ if (meta == NULL) ++ goto all_done; ++ } else { ++ if(meta->entries == 0) ++ goto failed; ++ /* XXX */ ++ offset = index < meta->offset + meta->entries ? index : ++ meta->offset + meta->entries - 1; ++ /* XXX */ ++ meta_entry = &meta->meta_entry[offset - meta->offset]; ++ cur_index_block = meta_entry->index_block + sblk->inode_table_start; ++ cur_offset = meta_entry->offset; ++ cur_data_block = meta_entry->data_block; ++ TRACE("get_meta_index: offset %d, meta->offset %d, " ++ "meta->entries %d\n", offset, meta->offset, meta->entries); ++ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x" ++ " data_block 0x%llx\n", cur_index_block, ++ cur_offset, cur_data_block); ++ } ++ ++ for (i = meta->offset + meta->entries; i <= index && ++ i < meta->offset + SQUASHFS_META_ENTRIES; i++) { ++ int blocks = skip * SQUASHFS_META_INDEXES; ++ ++ while (blocks) { ++ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : blocks; ++ int res = read_block_index(inode->i_sb, block, block_list, ++ &cur_index_block, &cur_offset); ++ ++ if (res == -1) ++ goto failed; ++ ++ cur_data_block += res; ++ blocks -= block; ++ } ++ ++ meta_entry = &meta->meta_entry[i - meta->offset]; ++ meta_entry->index_block = cur_index_block - sblk->inode_table_start; ++ meta_entry->offset = cur_offset; ++ meta_entry->data_block = cur_data_block; ++ meta->entries ++; ++ offset ++; ++ } ++ ++ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n", ++ meta->offset, meta->entries); ++ ++ release_meta_index(inode, meta); ++ } ++ ++all_done: ++ *index_block = cur_index_block; ++ *index_offset = cur_offset; ++ *data_block = cur_data_block; ++ ++ return offset * SQUASHFS_META_INDEXES * skip; ++ ++failed: ++ release_meta_index(inode, meta); ++ return -1; ++} ++ ++ ++static long long read_blocklist(struct inode *inode, int index, ++ int readahead_blks, char *block_list, ++ unsigned short **block_p, unsigned int *bsize) ++{ ++ long long block_ptr; ++ int offset; ++ long long block; ++ int res = get_meta_index(inode, index, &block_ptr, &offset, &block, ++ block_list); ++ ++ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset" ++ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, block); ++ ++ if(res == -1) ++ goto failure; ++ ++ index -= res; ++ ++ while (index) { ++ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index; ++ int res = read_block_index(inode->i_sb, blocks, block_list, ++ &block_ptr, &offset); ++ if (res == -1) ++ goto failure; ++ block += res; ++ index -= blocks; ++ } ++ ++ if (read_block_index(inode->i_sb, 1, block_list, &block_ptr, &offset) == -1) ++ goto failure; ++ *bsize = *((unsigned int *) block_list); ++ ++ return block; ++ ++failure: ++ return 0; ++} ++ ++ ++static int squashfs_readpage(struct file *file, struct page *page) ++{ ++ struct inode *inode = page->mapping->host; ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned char *block_list = NULL; ++ long long block; ++ unsigned int bsize, i; ++ int bytes; ++ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT); ++ void *pageaddr; ++ struct squashfs_fragment_cache *fragment = NULL; ++ char *data_ptr = msblk->read_page; ++ ++ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1; ++ int start_index = page->index & ~mask; ++ int end_index = start_index | mask; ++ int file_end = i_size_read(inode) >> sblk->block_log; ++ int sparse = 0; ++ ++ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", ++ page->index, SQUASHFS_I(inode)->start_block); ++ ++ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> ++ PAGE_CACHE_SHIFT)) ++ goto out; ++ ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK ++ || index < file_end) { ++ block_list = kmalloc(SIZE, GFP_KERNEL); ++ if (block_list == NULL) { ++ ERROR("Failed to allocate block_list\n"); ++ goto error_out; ++ } ++ ++ block = (msblk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize); ++ if (block == 0) ++ goto error_out; ++ ++ if (bsize == 0) { /* hole */ ++ bytes = index == file_end ? ++ (i_size_read(inode) & (sblk->block_size - 1)) : sblk->block_size; ++ sparse = 1; ++ } else { ++ mutex_lock(&msblk->read_page_mutex); ++ ++ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block, ++ bsize, NULL, sblk->block_size); ++ ++ if (bytes == 0) { ++ ERROR("Unable to read page, block %llx, size %x\n", block, bsize); ++ mutex_unlock(&msblk->read_page_mutex); ++ goto error_out; ++ } ++ } ++ } else { ++ fragment = get_cached_fragment(inode->i_sb, ++ SQUASHFS_I(inode)-> u.s1.fragment_start_block, ++ SQUASHFS_I(inode)->u.s1.fragment_size); ++ ++ if (fragment == NULL) { ++ ERROR("Unable to read page, block %llx, size %x\n", ++ SQUASHFS_I(inode)->u.s1.fragment_start_block, ++ (int) SQUASHFS_I(inode)->u.s1.fragment_size); ++ goto error_out; ++ } ++ bytes = i_size_read(inode) & (sblk->block_size - 1); ++ data_ptr = fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset; ++ } ++ ++ for (i = start_index; i <= end_index && bytes > 0; i++, ++ bytes -= PAGE_CACHE_SIZE, data_ptr += PAGE_CACHE_SIZE) { ++ struct page *push_page; ++ int avail = sparse ? 0 : min_t(unsigned int, bytes, PAGE_CACHE_SIZE); ++ ++ TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); ++ ++ push_page = (i == page->index) ? page : ++ grab_cache_page_nowait(page->mapping, i); ++ ++ if (!push_page) ++ continue; ++ ++ if (PageUptodate(push_page)) ++ goto skip_page; ++ ++ pageaddr = kmap_atomic(push_page, KM_USER0); ++ memcpy(pageaddr, data_ptr, avail); ++ memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); ++ kunmap_atomic(pageaddr, KM_USER0); ++ flush_dcache_page(push_page); ++ SetPageUptodate(push_page); ++skip_page: ++ unlock_page(push_page); ++ if(i != page->index) ++ page_cache_release(push_page); ++ } ++ ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK ++ || index < file_end) { ++ if (!sparse) ++ mutex_unlock(&msblk->read_page_mutex); ++ kfree(block_list); ++ } else ++ release_cached_fragment(msblk, fragment); ++ ++ return 0; ++ ++error_out: ++ SetPageError(page); ++out: ++ pageaddr = kmap_atomic(page, KM_USER0); ++ memset(pageaddr, 0, PAGE_CACHE_SIZE); ++ kunmap_atomic(pageaddr, KM_USER0); ++ flush_dcache_page(page); ++ if (!PageError(page)) ++ SetPageUptodate(page); ++ unlock_page(page); ++ ++ kfree(block_list); ++ return 0; ++} ++ ++ ++static int get_dir_index_using_offset(struct super_block *s, ++ long long *next_block, unsigned int *next_offset, ++ long long index_start, unsigned int index_offset, int i_count, ++ long long f_pos) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index index; ++ ++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", ++ i_count, (unsigned int) f_pos); ++ ++ f_pos =- 3; ++ if (f_pos == 0) ++ goto finish; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index sindex; ++ squashfs_get_cached_block(s, &sindex, index_start, index_offset, ++ sizeof(sindex), &index_start, &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); ++ } else ++ squashfs_get_cached_block(s, &index, index_start, index_offset, ++ sizeof(index), &index_start, &index_offset); ++ ++ if (index.index > f_pos) ++ break; ++ ++ squashfs_get_cached_block(s, NULL, index_start, index_offset, ++ index.size + 1, &index_start, &index_offset); ++ ++ length = index.index; ++ *next_block = index.start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ ++finish: ++ return length + 3; ++} ++ ++ ++static int get_dir_index_using_name(struct super_block *s, ++ long long *next_block, unsigned int *next_offset, ++ long long index_start, unsigned int index_offset, int i_count, ++ const char *name, int size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index *index; ++ char *str; ++ ++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); ++ ++ str = kmalloc(sizeof(struct squashfs_dir_index) + ++ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL); ++ if (str == NULL) { ++ ERROR("Failed to allocate squashfs_dir_index\n"); ++ goto failure; ++ } ++ ++ index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1); ++ strncpy(str, name, size); ++ str[size] = '\0'; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index sindex; ++ squashfs_get_cached_block(s, &sindex, index_start, index_offset, ++ sizeof(sindex), &index_start, &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX(index, &sindex); ++ } else ++ squashfs_get_cached_block(s, index, index_start, index_offset, ++ sizeof(struct squashfs_dir_index), &index_start, &index_offset); ++ ++ squashfs_get_cached_block(s, index->name, index_start, index_offset, ++ index->size + 1, &index_start, &index_offset); ++ ++ index->name[index->size + 1] = '\0'; ++ ++ if (strcmp(index->name, str) > 0) ++ break; ++ ++ length = index->index; ++ *next_block = index->start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ kfree(str); ++ ++failure: ++ return length + 3; ++} ++ ++ ++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) ++{ ++ struct inode *i = file->f_dentry->d_inode; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; ++ struct squashfs_dir_header dirh; ++ struct squashfs_dir_entry *dire; ++ ++ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset); ++ ++ dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL); ++ if (dire == NULL) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto finish; ++ } ++ ++ while(file->f_pos < 3) { ++ char *name; ++ int size, i_ino; ++ ++ if(file->f_pos == 0) { ++ name = "."; ++ size = 1; ++ i_ino = i->i_ino; ++ } else { ++ name = ".."; ++ size = 2; ++ i_ino = SQUASHFS_I(i)->u.s2.parent_inode; ++ } ++ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n", ++ (unsigned int) dirent, name, size, (int) ++ file->f_pos, i_ino, squashfs_filetype_table[1]); ++ ++ if (filldir(dirent, name, size, file->f_pos, i_ino, ++ squashfs_filetype_table[1]) < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos += size; ++ } ++ ++ length = get_dir_index_using_offset(i->i_sb, &next_block, ++ (unsigned int *)&next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, file->f_pos); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header sdirh; ++ ++ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block, ++ next_offset, sizeof(sdirh), &next_block, ++ (unsigned int *)&next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block, ++ next_offset, sizeof(dirh), &next_block, ++ (unsigned int *)&next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry sdire; ++ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block, ++ next_offset, sizeof(sdire), &next_block, ++ (unsigned int *)&next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, dire, next_block, ++ next_offset, sizeof(*dire), &next_block, ++ (unsigned int *)&next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, ++ next_offset, dire->size + 1, &next_block, ++ (unsigned int *)&next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (file->f_pos >= length) ++ continue; ++ ++ dire->name[dire->size + 1] = '\0'; ++ ++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n", ++ (unsigned int) dirent, dire->name, dire->size + 1, ++ (int) file->f_pos, dirh.start_block, dire->offset, ++ dirh.inode_number + dire->inode_number, ++ squashfs_filetype_table[dire->type]); ++ ++ if (filldir(dirent, dire->name, dire->size + 1, file->f_pos, ++ dirh.inode_number + dire->inode_number, ++ squashfs_filetype_table[dire->type]) < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos = length; ++ } ++ } ++ ++finish: ++ kfree(dire); ++ return 0; ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ kfree(dire); ++ return 0; ++} ++ ++ ++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ const unsigned char *name = dentry->d_name.name; ++ int len = dentry->d_name.len; ++ struct inode *inode = NULL; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count; ++ struct squashfs_dir_header dirh; ++ struct squashfs_dir_entry *dire; ++ ++ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset); ++ ++ dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL); ++ if (dire == NULL) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto exit_lookup; ++ } ++ ++ if (len > SQUASHFS_NAME_LEN) ++ goto exit_lookup; ++ ++ length = get_dir_index_using_name(i->i_sb, &next_block, (unsigned int *)&next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, name, len); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header sdirh; ++ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block, ++ next_offset, sizeof(sdirh), &next_block, ++ (unsigned int *)&next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block, ++ next_offset, sizeof(dirh), &next_block, ++ (unsigned int *)&next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry sdire; ++ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block, ++ next_offset, sizeof(sdire), &next_block, ++ (unsigned int *)&next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, dire, next_block, ++ next_offset, sizeof(*dire), &next_block, ++ (unsigned int *)&next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block, ++ next_offset, dire->size + 1, &next_block, ++ (unsigned int *)&next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (name[0] < dire->name[0]) ++ goto exit_lookup; ++ ++ if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) { ++ squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block, ++ dire->offset); ++ ++ TRACE("calling squashfs_iget for directory entry %s, inode" ++ " %x:%x, %d\n", name, dirh.start_block, dire->offset, ++ dirh.inode_number + dire->inode_number); ++ ++ inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number); ++ ++ goto exit_lookup; ++ } ++ } ++ } ++ ++exit_lookup: ++ kfree(dire); ++ if (inode) ++ return d_splice_alias(inode, dentry); ++ d_add(dentry, inode); ++ return ERR_PTR(0); ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ goto exit_lookup; ++} ++ ++ ++static int squashfs_remount(struct super_block *s, int *flags, char *data) ++{ ++ *flags |= MS_RDONLY; ++ return 0; ++} ++ ++ ++static void squashfs_put_super(struct super_block *s) ++{ ++ int i; ++ ++ if (s->s_fs_info) { ++ struct squashfs_sb_info *sbi = s->s_fs_info; ++ if (sbi->block_cache) ++ for (i = 0; i < squashfs_cached_blks; i++) ++ if (sbi->block_cache[i].block != SQUASHFS_INVALID_BLK) ++ vfree(sbi->block_cache[i].data); ++ if (sbi->fragment) ++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) ++ vfree(sbi->fragment[i].data); ++ kfree(sbi->fragment); ++ kfree(sbi->block_cache); ++ vfree(sbi->read_page); ++ kfree(sbi->uid); ++ kfree(sbi->fragment_index); ++ kfree(sbi->fragment_index_2); ++ kfree(sbi->meta_index); ++ kfree(s->s_fs_info); ++ s->s_fs_info = NULL; ++ } ++} ++ ++ ++static int squashfs_get_sb(struct file_system_type *fs_type, int flags, ++ const char *dev_name, void *data, struct vfsmount *mnt) ++{ ++ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, ++ mnt); ++} ++ ++static void free_sqlzma(void) ++{ ++ int cpu; ++ struct sqlzma *p; ++ ++ for_each_online_cpu(cpu) { ++ p = per_cpu(sqlzma, cpu); ++ if (p) { ++#ifdef KeepPreemptive ++ mutex_destroy(&p->mtx); ++#endif ++ sqlzma_fin(&p->un); ++ kfree(p); ++ } ++ } ++} ++ ++static int __init init_squashfs_fs(void) ++{ ++ struct sqlzma *p; ++ int cpu; ++ int err = init_inodecache(); ++ if (err) ++ goto out; ++ ++ for_each_online_cpu(cpu) { ++ dpri("%d: %p\n", cpu, per_cpu(sqlzma, cpu)); ++ err = -ENOMEM; ++ p = kmalloc(sizeof(struct sqlzma), GFP_KERNEL); ++ if (p) { ++#ifdef KeepPreemptive ++ mutex_init(&p->mtx); ++#endif ++ err = sqlzma_init(&p->un, 1, 0); ++ if (unlikely(err)) { ++ ERROR("Failed to intialize uncompress workspace\n"); ++ break; ++ } ++ per_cpu(sqlzma, cpu) = p; ++ err = 0; ++ } else ++ break; ++ } ++ if (unlikely(err)) { ++ free_sqlzma(); ++ goto out; ++ } ++ ++ printk(KERN_INFO "squashfs: version 3.3 (2007/10/31) " ++ "Phillip Lougher\n" ++ "squashfs: LZMA suppport for slax.org by jro\n"); ++ ++ err = register_filesystem(&squashfs_fs_type); ++ if (err) { ++ free_sqlzma(); ++ destroy_inodecache(); ++ } ++ ++out: ++ return err; ++} ++ ++ ++static void __exit exit_squashfs_fs(void) ++{ ++ unregister_filesystem(&squashfs_fs_type); ++ free_sqlzma(); ++ destroy_inodecache(); ++} ++ ++ ++static struct kmem_cache * squashfs_inode_cachep; ++ ++ ++static struct inode *squashfs_alloc_inode(struct super_block *sb) ++{ ++ struct squashfs_inode_info *ei; ++ ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); ++ return ei ? &ei->vfs_inode : NULL; ++} ++ ++ ++static void squashfs_destroy_inode(struct inode *inode) ++{ ++ kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode)); ++} ++ ++ ++static void init_once(struct kmem_cache *cachep, void *foo) ++{ ++ struct squashfs_inode_info *ei = foo; ++ ++ inode_init_once(&ei->vfs_inode); ++} ++ ++ ++static int __init init_inodecache(void) ++{ ++ squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", ++ sizeof(struct squashfs_inode_info), 0, ++ SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once); ++ if (squashfs_inode_cachep == NULL) ++ return -ENOMEM; ++ return 0; ++} ++ ++ ++static void destroy_inodecache(void) ++{ ++ kmem_cache_destroy(squashfs_inode_cachep); ++} ++ ++ ++module_init(init_squashfs_fs); ++module_exit(exit_squashfs_fs); ++MODULE_DESCRIPTION("squashfs 3.2-r2-CVS, a compressed read-only filesystem, and LZMA suppport for slax.org"); ++MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>, and LZMA suppport for slax.org by jro"); ++MODULE_LICENSE("GPL"); +diff -urN linux-2.6.23/fs/squashfs/module.c linux-2.6.23.sqlzma-ng/fs/squashfs/module.c +--- linux-2.6.23/fs/squashfs/module.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/fs/squashfs/module.c 2007-11-13 19:51:33.000000000 -0500 +@@ -0,0 +1,36 @@ ++ ++/* ++ * Copyright (C) 2006-2007 Junjiro Okajima ++ * Copyright (C) 2006-2007 Tomas Matejicek, slax.org ++ * ++ * LICENSE follows the described one in lzma.txt. ++ */ ++ ++/* $Id: module.c,v 1.1 2007/11/05 05:43:36 jro Exp $ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++ ++#include "LzmaDecode.c" ++ ++EXPORT_SYMBOL(LzmaDecodeProperties); ++EXPORT_SYMBOL(LzmaDecode); ++ ++#if 0 ++static int __init unlzma_init(void) ++{ ++ return 0; ++} ++ ++static void __exit unlzma_exit(void) ++{ ++} ++ ++module_init(unlzma_init); ++module_exit(unlzma_exit); ++#endif ++ ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("$Id: module.c,v 1.1 2007/11/05 05:43:36 jro Exp $"); ++MODULE_DESCRIPTION("LZMA uncompress. " ++ "A tiny wrapper for LzmaDecode.c in LZMA SDK from www.7-zip.org."); +diff -urN linux-2.6.23/fs/squashfs/sqlzma.h linux-2.6.23.sqlzma-ng/fs/squashfs/sqlzma.h +--- linux-2.6.23/fs/squashfs/sqlzma.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/fs/squashfs/sqlzma.h 2007-11-13 19:09:21.000000000 -0500 +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (C) 2006 Junjiro Okajima ++ * Copyright (C) 2006 Tomas Matejicek, slax.org ++ * ++ * LICENSE follows the described one in lzma. ++ */ ++ ++/* $Id: sqlzma.h,v 1.15 2007/11/09 14:42:12 jro Exp $ */ ++ ++#ifndef __sqlzma_h__ ++#define __sqlzma_h__ ++ ++#ifndef __KERNEL__ ++#include <stdlib.h> ++#include <string.h> ++#include <zlib.h> ++#ifdef _REENTRANT ++#include <pthread.h> ++#endif ++#else ++#include <linux/zlib.h> ++#endif ++#define _7ZIP_BYTE_DEFINED ++ ++/* ++ * detect the compression method automatically by the first byte of compressed ++ * data. ++ * according to rfc1950, the first byte of zlib compression must be 0x?8. ++ */ ++#define is_lzma(c) (c == 0x5d) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#ifndef __KERNEL__ ++/* for mksquashfs only */ ++struct sqlzma_opts { ++ unsigned int try_lzma:1; ++ unsigned int dicsize; ++}; ++int sqlzma_cm(struct sqlzma_opts *opts, z_stream *stream, Bytef *next_in, uInt ++ avail_in, Bytef *next_out, uInt avail_out); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Three patterns for sqlzma uncompression. very dirty code. ++ * - kernel space (squashfs kernel module) ++ * - user space with pthread (mksquashfs) ++ * - user space without pthread (unsquashfs) ++ */ ++ ++struct sized_buf { ++ unsigned int sz; ++ unsigned char *buf; ++}; ++ ++enum {SQUN_PROB, SQUN_RESULT, SQUN_LAST}; ++struct sqlzma_un { ++ int un_lzma; ++ struct sized_buf un_a[SQUN_LAST]; ++ unsigned char un_prob[31960]; /* unlzma 64KB - 1MB */ ++ z_stream un_stream; ++#define un_cmbuf un_stream.next_in ++#define un_cmlen un_stream.avail_in ++#define un_resbuf un_stream.next_out ++#define un_resroom un_stream.avail_out ++#define un_reslen un_stream.total_out ++}; ++ ++int sqlzma_init(struct sqlzma_un *un, int do_lzma, unsigned int res_sz); ++int sqlzma_un(struct sqlzma_un *un, struct sized_buf *src, struct sized_buf *dst); ++void sqlzma_fin(struct sqlzma_un *un); ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef __cplusplus ++}; ++#endif ++#endif +diff -urN linux-2.6.23/fs/squashfs/squashfs.h linux-2.6.23.sqlzma-ng/fs/squashfs/squashfs.h +--- linux-2.6.23/fs/squashfs/squashfs.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/fs/squashfs/squashfs.h 2007-11-13 18:58:41.000000000 -0500 +@@ -0,0 +1,86 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher <phillip@lougher.demon.co.uk> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs.h ++ */ ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++#endif ++ ++#ifdef SQUASHFS_TRACE ++#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) ++#else ++#define TRACE(s, args...) {} ++#endif ++ ++#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) ++ ++#define SERROR(s, args...) do { \ ++ if (!silent) \ ++ printk(KERN_ERR "SQUASHFS error: "s, ## args);\ ++ } while(0) ++ ++#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) ++ ++static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode) ++{ ++ return list_entry(inode, struct squashfs_inode_info, vfs_inode); ++} ++ ++#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY) ++#define SQSH_EXTERN ++extern unsigned int squashfs_read_data(struct super_block *s, char *buffer, ++ long long index, unsigned int length, ++ long long *next_index, int srclength); ++extern int squashfs_get_cached_block(struct super_block *s, void *buffer, ++ long long block, unsigned int offset, ++ int length, long long *next_block, ++ unsigned int *next_offset); ++extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct ++ squashfs_fragment_cache *fragment); ++extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block ++ *s, long long start_block, ++ int length); ++extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number); ++extern const struct address_space_operations squashfs_symlink_aops; ++extern const struct address_space_operations squashfs_aops; ++extern struct inode_operations squashfs_dir_inode_ops; ++#else ++#define SQSH_EXTERN static ++#endif ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk); ++#else ++static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk) ++{ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk); ++#else ++static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk) ++{ ++ return 0; ++} ++#endif +diff -urN linux-2.6.23/fs/squashfs/squashfs2_0.c linux-2.6.23.sqlzma-ng/fs/squashfs/squashfs2_0.c +--- linux-2.6.23/fs/squashfs/squashfs2_0.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/fs/squashfs/squashfs2_0.c 2007-11-13 18:58:41.000000000 -0500 +@@ -0,0 +1,740 @@ ++/* ++ * Squashfs - a compressed read only filesystem for Linux ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher <phillip@lougher.demon.co.uk> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs2_0.c ++ */ ++ ++#include <linux/squashfs_fs.h> ++#include <linux/module.h> ++#include <linux/zlib.h> ++#include <linux/fs.h> ++#include <linux/squashfs_fs_sb.h> ++#include <linux/squashfs_fs_i.h> ++ ++#include "squashfs.h" ++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir); ++static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *, ++ struct nameidata *); ++ ++static struct file_operations squashfs_dir_ops_2 = { ++ .read = generic_read_dir, ++ .readdir = squashfs_readdir_2 ++}; ++ ++static struct inode_operations squashfs_dir_inode_ops_2 = { ++ .lookup = squashfs_lookup_2 ++}; ++ ++static unsigned char squashfs_filetype_table[] = { ++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK ++}; ++ ++static int read_fragment_index_table_2(struct super_block *s) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2 ++ (sblk->fragments), GFP_KERNEL))) { ++ ERROR("Failed to allocate uid/gid table\n"); ++ return 0; ++ } ++ ++ if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) && ++ !squashfs_read_data(s, (char *) ++ msblk->fragment_index_2, ++ sblk->fragment_table_start, ++ SQUASHFS_FRAGMENT_INDEX_BYTES_2 ++ (sblk->fragments) | ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) { ++ ERROR("unable to read fragment index table\n"); ++ return 0; ++ } ++ ++ if (msblk->swap) { ++ int i; ++ unsigned int fragment; ++ ++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments); ++ i++) { ++ SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment), ++ &msblk->fragment_index_2[i], 1); ++ msblk->fragment_index_2[i] = fragment; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++static int get_fragment_location_2(struct super_block *s, unsigned int fragment, ++ long long *fragment_start_block, ++ unsigned int *fragment_size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ long long start_block = ++ msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)]; ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment); ++ struct squashfs_fragment_entry_2 fragment_entry; ++ ++ if (msblk->swap) { ++ struct squashfs_fragment_entry_2 sfragment_entry; ++ ++ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, ++ start_block, offset, ++ sizeof(sfragment_entry), &start_block, ++ &offset)) ++ goto out; ++ SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) &fragment_entry, ++ start_block, offset, ++ sizeof(fragment_entry), &start_block, ++ &offset)) ++ goto out; ++ ++ *fragment_start_block = fragment_entry.start_block; ++ *fragment_size = fragment_entry.size; ++ ++ return 1; ++ ++out: ++ return 0; ++} ++ ++ ++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, ++ struct squashfs_base_inode_header_2 *inodeb, unsigned int ino) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ i->i_ino = ino; ++ i->i_mtime.tv_sec = sblk->mkfs_time; ++ i->i_atime.tv_sec = sblk->mkfs_time; ++ i->i_ctime.tv_sec = sblk->mkfs_time; ++ i->i_uid = msblk->uid[inodeb->uid]; ++ i->i_mode = inodeb->mode; ++ i->i_nlink = 1; ++ i->i_size = 0; ++ if (inodeb->guid == SQUASHFS_GUIDS) ++ i->i_gid = i->i_uid; ++ else ++ i->i_gid = msblk->guid[inodeb->guid]; ++} ++ ++ ++static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode) ++{ ++ struct super_block *s = i->i_sb; ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ unsigned int block = SQUASHFS_INODE_BLK(inode) + ++ sblk->inode_table_start; ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode); ++ unsigned int ino = SQUASHFS_MK_VFS_INODE(block - ++ sblk->inode_table_start, offset); ++ long long next_block; ++ unsigned int next_offset; ++ union squashfs_inode_header_2 id, sid; ++ struct squashfs_base_inode_header_2 *inodeb = &id.base, ++ *sinodeb = &sid.base; ++ ++ TRACE("Entered squashfs_read_inode_2\n"); ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) sinodeb, block, ++ offset, sizeof(*sinodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb, ++ sizeof(*sinodeb)); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) inodeb, block, ++ offset, sizeof(*inodeb), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ squashfs_new_inode(msblk, i, inodeb, ino); ++ ++ switch(inodeb->inode_type) { ++ case SQUASHFS_FILE_TYPE: { ++ struct squashfs_reg_inode_header_2 *inodep = &id.reg; ++ struct squashfs_reg_inode_header_2 *sinodep = &sid.reg; ++ long long frag_blk; ++ unsigned int frag_size = 0; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ frag_blk = SQUASHFS_INVALID_BLK; ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG && ++ !get_fragment_location_2(s, ++ inodep->fragment, &frag_blk, &frag_size)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_fop = &generic_ro_fops; ++ i->i_mode |= S_IFREG; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1; ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size; ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ i->i_data.a_ops = &squashfs_aops; ++ ++ TRACE("File inode %x:%x, start_block %x, " ++ "block_list_start %llx, offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, next_block, ++ next_offset); ++ break; ++ } ++ case SQUASHFS_DIR_TYPE: { ++ struct squashfs_dir_inode_header_2 *inodep = &id.dir; ++ struct squashfs_dir_inode_header_2 *sinodep = &sid.dir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops_2; ++ i->i_fop = &squashfs_dir_ops_2; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = 0; ++ SQUASHFS_I(i)->u.s2.parent_inode = 0; ++ ++ TRACE("Directory inode %x:%x, start_block %x, offset " ++ "%x\n", SQUASHFS_INODE_BLK(inode), ++ offset, inodep->start_block, ++ inodep->offset); ++ break; ++ } ++ case SQUASHFS_LDIR_TYPE: { ++ struct squashfs_ldir_inode_header_2 *inodep = &id.ldir; ++ struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->file_size; ++ i->i_op = &squashfs_dir_inode_ops_2; ++ i->i_fop = &squashfs_dir_ops_2; ++ i->i_mode |= S_IFDIR; ++ i->i_mtime.tv_sec = inodep->mtime; ++ i->i_atime.tv_sec = inodep->mtime; ++ i->i_ctime.tv_sec = inodep->mtime; ++ SQUASHFS_I(i)->start_block = inodep->start_block; ++ SQUASHFS_I(i)->offset = inodep->offset; ++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block; ++ SQUASHFS_I(i)->u.s2.directory_index_offset = ++ next_offset; ++ SQUASHFS_I(i)->u.s2.directory_index_count = ++ inodep->i_count; ++ SQUASHFS_I(i)->u.s2.parent_inode = 0; ++ ++ TRACE("Long directory inode %x:%x, start_block %x, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->start_block, inodep->offset); ++ break; ++ } ++ case SQUASHFS_SYMLINK_TYPE: { ++ struct squashfs_symlink_inode_header_2 *inodep = ++ &id.symlink; ++ struct squashfs_symlink_inode_header_2 *sinodep = ++ &sid.symlink; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, ++ sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_size = inodep->symlink_size; ++ i->i_op = &page_symlink_inode_operations; ++ i->i_data.a_ops = &squashfs_symlink_aops; ++ i->i_mode |= S_IFLNK; ++ SQUASHFS_I(i)->start_block = next_block; ++ SQUASHFS_I(i)->offset = next_offset; ++ ++ TRACE("Symbolic link inode %x:%x, start_block %llx, " ++ "offset %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ next_block, next_offset); ++ break; ++ } ++ case SQUASHFS_BLKDEV_TYPE: ++ case SQUASHFS_CHRDEV_TYPE: { ++ struct squashfs_dev_inode_header_2 *inodep = &id.dev; ++ struct squashfs_dev_inode_header_2 *sinodep = &sid.dev; ++ ++ if (msblk->swap) { ++ if (!squashfs_get_cached_block(s, (char *) ++ sinodep, block, offset, ++ sizeof(*sinodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep); ++ } else ++ if (!squashfs_get_cached_block(s, (char *) ++ inodep, block, offset, ++ sizeof(*inodep), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ i->i_mode |= (inodeb->inode_type == ++ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : ++ S_IFBLK; ++ init_special_inode(i, i->i_mode, ++ old_decode_dev(inodep->rdev)); ++ ++ TRACE("Device inode %x:%x, rdev %x\n", ++ SQUASHFS_INODE_BLK(inode), offset, ++ inodep->rdev); ++ break; ++ } ++ case SQUASHFS_FIFO_TYPE: ++ case SQUASHFS_SOCKET_TYPE: { ++ ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) ++ ? S_IFIFO : S_IFSOCK; ++ init_special_inode(i, i->i_mode, 0); ++ break; ++ } ++ default: ++ ERROR("Unknown inode type %d in squashfs_iget!\n", ++ inodeb->inode_type); ++ goto failed_read1; ++ } ++ ++ return 1; ++ ++failed_read: ++ ERROR("Unable to read inode [%x:%x]\n", block, offset); ++ ++failed_read1: ++ return 0; ++} ++ ++ ++static int get_dir_index_using_offset(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ long long f_pos) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index_2 index; ++ ++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", ++ i_count, (unsigned int) f_pos); ++ ++ if (f_pos == 0) ++ goto finish; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index_2 sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) &index, ++ index_start, index_offset, ++ sizeof(index), &index_start, ++ &index_offset); ++ ++ if (index.index > f_pos) ++ break; ++ ++ squashfs_get_cached_block(s, NULL, index_start, index_offset, ++ index.size + 1, &index_start, ++ &index_offset); ++ ++ length = index.index; ++ *next_block = index.start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ ++finish: ++ return length; ++} ++ ++ ++static int get_dir_index_using_name(struct super_block *s, long long ++ *next_block, unsigned int *next_offset, ++ long long index_start, ++ unsigned int index_offset, int i_count, ++ const char *name, int size) ++{ ++ struct squashfs_sb_info *msblk = s->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ int i, length = 0; ++ struct squashfs_dir_index_2 *index; ++ char *str; ++ ++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); ++ ++ if (!(str = kmalloc(sizeof(struct squashfs_dir_index) + ++ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_index\n"); ++ goto failure; ++ } ++ ++ index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1); ++ strncpy(str, name, size); ++ str[size] = '\0'; ++ ++ for (i = 0; i < i_count; i++) { ++ if (msblk->swap) { ++ struct squashfs_dir_index_2 sindex; ++ squashfs_get_cached_block(s, (char *) &sindex, ++ index_start, index_offset, ++ sizeof(sindex), &index_start, ++ &index_offset); ++ SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex); ++ } else ++ squashfs_get_cached_block(s, (char *) index, ++ index_start, index_offset, ++ sizeof(struct squashfs_dir_index_2), ++ &index_start, &index_offset); ++ ++ squashfs_get_cached_block(s, index->name, index_start, ++ index_offset, index->size + 1, ++ &index_start, &index_offset); ++ ++ index->name[index->size + 1] = '\0'; ++ ++ if (strcmp(index->name, str) > 0) ++ break; ++ ++ length = index->index; ++ *next_block = index->start_block + sblk->directory_table_start; ++ } ++ ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; ++ kfree(str); ++failure: ++ return length; ++} ++ ++ ++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir) ++{ ++ struct inode *i = file->f_dentry->d_inode; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header_2 dirh; ++ struct squashfs_dir_entry_2 *dire; ++ ++ TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto finish; ++ } ++ ++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, ++ file->f_pos); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header_2 sdirh; ++ ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry_2 sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block, next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block, next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, ++ dire->size + 1, &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (file->f_pos >= length) ++ continue; ++ ++ dire->name[dire->size + 1] = '\0'; ++ ++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", ++ (unsigned int) dirent, dire->name, ++ dire->size + 1, (int) file->f_pos, ++ dirh.start_block, dire->offset, ++ squashfs_filetype_table[dire->type]); ++ ++ if (filldir(dirent, dire->name, dire->size + 1, ++ file->f_pos, SQUASHFS_MK_VFS_INODE( ++ dirh.start_block, dire->offset), ++ squashfs_filetype_table[dire->type]) ++ < 0) { ++ TRACE("Filldir returned less than 0\n"); ++ goto finish; ++ } ++ file->f_pos = length; ++ } ++ } ++ ++finish: ++ kfree(dire); ++ return 0; ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ kfree(dire); ++ return 0; ++} ++ ++ ++static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry, ++ struct nameidata *nd) ++{ ++ const unsigned char *name = dentry->d_name.name; ++ int len = dentry->d_name.len; ++ struct inode *inode = NULL; ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ long long next_block = SQUASHFS_I(i)->start_block + ++ sblk->directory_table_start; ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, ++ dir_count; ++ struct squashfs_dir_header_2 dirh; ++ struct squashfs_dir_entry_2 *dire; ++ int sorted = sblk->s_major == 2 && sblk->s_minor >= 1; ++ ++ TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset); ++ ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { ++ ERROR("Failed to allocate squashfs_dir_entry\n"); ++ goto exit_loop; ++ } ++ ++ if (len > SQUASHFS_NAME_LEN) ++ goto exit_loop; ++ ++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_start, ++ SQUASHFS_I(i)->u.s2.directory_index_offset, ++ SQUASHFS_I(i)->u.s2.directory_index_count, name, ++ len); ++ ++ while (length < i_size_read(i)) { ++ /* read directory header */ ++ if (msblk->swap) { ++ struct squashfs_dir_header_2 sdirh; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, ++ next_block, next_offset, sizeof(sdirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdirh); ++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, ++ next_block, next_offset, sizeof(dirh), ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(dirh); ++ } ++ ++ dir_count = dirh.count + 1; ++ while (dir_count--) { ++ if (msblk->swap) { ++ struct squashfs_dir_entry_2 sdire; ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ &sdire, next_block,next_offset, ++ sizeof(sdire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(sdire); ++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); ++ } else { ++ if (!squashfs_get_cached_block(i->i_sb, (char *) ++ dire, next_block,next_offset, ++ sizeof(*dire), &next_block, ++ &next_offset)) ++ goto failed_read; ++ ++ length += sizeof(*dire); ++ } ++ ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, ++ next_block, next_offset, dire->size + 1, ++ &next_block, &next_offset)) ++ goto failed_read; ++ ++ length += dire->size + 1; ++ ++ if (sorted && name[0] < dire->name[0]) ++ goto exit_loop; ++ ++ if ((len == dire->size + 1) && !strncmp(name, ++ dire->name, len)) { ++ squashfs_inode_t ino = ++ SQUASHFS_MKINODE(dirh.start_block, ++ dire->offset); ++ unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block, ++ dire->offset); ++ ++ TRACE("calling squashfs_iget for directory " ++ "entry %s, inode %x:%x, %lld\n", name, ++ dirh.start_block, dire->offset, ino); ++ ++ inode = squashfs_iget(i->i_sb, ino, inode_number); ++ ++ goto exit_loop; ++ } ++ } ++ } ++ ++exit_loop: ++ kfree(dire); ++ d_add(dentry, inode); ++ return ERR_PTR(0); ++ ++failed_read: ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block, ++ next_offset); ++ goto exit_loop; ++} ++ ++ ++int squashfs_2_0_supported(struct squashfs_sb_info *msblk) ++{ ++ struct squashfs_super_block *sblk = &msblk->sblk; ++ ++ msblk->read_inode = squashfs_read_inode_2; ++ msblk->read_fragment_index_table = read_fragment_index_table_2; ++ ++ sblk->bytes_used = sblk->bytes_used_2; ++ sblk->uid_start = sblk->uid_start_2; ++ sblk->guid_start = sblk->guid_start_2; ++ sblk->inode_table_start = sblk->inode_table_start_2; ++ sblk->directory_table_start = sblk->directory_table_start_2; ++ sblk->fragment_table_start = sblk->fragment_table_start_2; ++ ++ return 1; ++} +diff -urN linux-2.6.23/fs/squashfs/uncomp.c linux-2.6.23.sqlzma-ng/fs/squashfs/uncomp.c +--- linux-2.6.23/fs/squashfs/uncomp.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/fs/squashfs/uncomp.c 2007-11-13 19:40:29.000000000 -0500 +@@ -0,0 +1,221 @@ ++/* ++ * Copyright (C) 2006, 2007 Junjiro Okajima ++ * Copyright (C) 2006, 2007 Tomas Matejicek, slax.org ++ * ++ * LICENSE follows the described one in lzma.txt. ++ */ ++ ++/* $Id: uncomp.c,v 1.1 2007/11/05 05:43:36 jro Exp $ */ ++ ++/* extract some parts from lzma443/C/7zip/Compress/LZMA_C/LzmaTest.c */ ++ ++#ifndef __KERNEL__ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <errno.h> ++#include <assert.h> ++#include <pthread.h> ++#define unlikely(x) __builtin_expect(!!(x), 0) ++#define BUG_ON(x) assert(!(x)) ++/* sqlzma buffers are always larger than a page. true? */ ++#define kmalloc(sz,gfp) malloc(sz) ++#define kfree(p) free(p) ++#define zlib_inflate(s, f) inflate(s, f) ++#define zlib_inflateInit(s) inflateInit(s) ++#define zlib_inflateReset(s) inflateReset(s) ++#define zlib_inflateEnd(s) inflateEnd(s) ++#else ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/vmalloc.h> ++#ifndef WARN_ON_ONCE ++#define WARN_ON_ONCE(b) WARN_ON(b) ++#endif ++#endif /* __KERNEL__ */ ++ ++#include "sqlzma.h" ++#include "LzmaDecode.h" ++ ++static int LzmaUncompress(struct sqlzma_un *un) ++{ ++ int err, i, ret; ++ SizeT outSize, inProcessed, outProcessed, srclen; ++ /* it's about 24-80 bytes structure, if int is 32-bit */ ++ CLzmaDecoderState state; ++ unsigned char *dst, *src, a[8]; ++ struct sized_buf *sbuf; ++ ++ /* Decode LZMA properties and allocate memory */ ++ err = -EINVAL; ++ src = un->un_cmbuf; ++ ret = LzmaDecodeProperties(&state.Properties, src, LZMA_PROPERTIES_SIZE); ++ src += LZMA_PROPERTIES_SIZE; ++ if (unlikely(ret != LZMA_RESULT_OK)) ++ goto out; ++ i = LzmaGetNumProbs(&state.Properties); ++ if (unlikely(i <= 0)) ++ i = 1; ++ i *= sizeof(CProb); ++ sbuf = un->un_a + SQUN_PROB; ++ if (unlikely(sbuf->sz < i)) { ++ if (sbuf->buf && sbuf->buf != un->un_prob) ++ kfree(sbuf->buf); ++#ifdef __KERNEL__ ++ printk("%s:%d: %d --> %d\n", __func__, __LINE__, sbuf->sz, i); ++#else ++ printf("%d --> %d\n", sbuf->sz, i); ++#endif ++ err = -ENOMEM; ++ sbuf->sz = 0; ++ sbuf->buf = kmalloc(i, GFP_ATOMIC); ++ if (unlikely(!sbuf->buf)) ++ goto out; ++ sbuf->sz = i; ++ } ++ state.Probs = (void*)sbuf->buf; ++ ++ /* Read uncompressed size */ ++ memcpy(a, src, sizeof(a)); ++ src += sizeof(a); ++ outSize = a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24); ++ ++ err = -EINVAL; ++ dst = un->un_resbuf; ++ if (unlikely(!dst || outSize > un->un_reslen)) ++ goto out; ++ un->un_reslen = outSize; ++ srclen = un->un_cmlen - (src - un->un_cmbuf); ++ ++ /* Decompress */ ++ err = LzmaDecode(&state, src, srclen, &inProcessed, dst, outSize, ++ &outProcessed); ++ if (err) ++ err = -EINVAL; ++ ++ out: ++#ifndef __KERNEL__ ++ if (err) ++ fprintf(stderr, "err %d\n", err); ++#endif ++ return err; ++} ++ ++int sqlzma_un(struct sqlzma_un *un, struct sized_buf *src, ++ struct sized_buf *dst) ++{ ++ int err, by_lzma = 0; ++ if (un->un_lzma && is_lzma(*src->buf)) { ++ by_lzma = 1; ++ un->un_cmbuf = src->buf; ++ un->un_cmlen = src->sz; ++ un->un_resbuf = dst->buf; ++ un->un_reslen = dst->sz; ++ ++ /* this library is thread-safe */ ++ err = LzmaUncompress(un); ++ goto out; ++ } ++ ++ err = zlib_inflateReset(&un->un_stream); ++ if (unlikely(err != Z_OK)) ++ goto out; ++ un->un_stream.next_in = src->buf; ++ un->un_stream.avail_in = src->sz; ++ un->un_stream.next_out = dst->buf; ++ un->un_stream.avail_out = dst->sz; ++ err = zlib_inflate(&un->un_stream, Z_FINISH); ++ if (err == Z_STREAM_END) ++ err = 0; ++ ++ out: ++ if (err) { ++#ifdef __KERNEL__ ++ WARN_ON_ONCE(1); ++#else ++ char a[64] = "ZLIB "; ++ if (by_lzma) { ++ strcpy(a, "LZMA "); ++#ifdef _REENTRANT ++ strerror_r(err, a + 5, sizeof(a) - 5); ++#else ++ strncat(a, strerror(err), sizeof(a) - 5); ++#endif ++ } else ++ strncat(a, zError(err), sizeof(a) - 5); ++ fprintf(stderr, "%s: %.*s\n", __func__, sizeof(a), a); ++#endif ++ } ++ return err; ++} ++ ++int sqlzma_init(struct sqlzma_un *un, int do_lzma, unsigned int res_sz) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ un->un_lzma = do_lzma; ++ memset(un->un_a, 0, sizeof(un->un_a)); ++ un->un_a[SQUN_PROB].buf = un->un_prob; ++ un->un_a[SQUN_PROB].sz = sizeof(un->un_prob); ++ if (res_sz) { ++ un->un_a[SQUN_RESULT].buf = kmalloc(res_sz, GFP_KERNEL); ++ if (unlikely(!un->un_a[SQUN_RESULT].buf)) ++ return err; ++ un->un_a[SQUN_RESULT].sz = res_sz; ++ } ++ ++ un->un_stream.next_in = NULL; ++ un->un_stream.avail_in = 0; ++#ifdef __KERNEL__ ++ un->un_stream.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); ++ if (unlikely(!un->un_stream.workspace)) ++ return err; ++#else ++ un->un_stream.opaque = NULL; ++ un->un_stream.zalloc = Z_NULL; ++ un->un_stream.zfree = Z_NULL; ++#endif ++ err = zlib_inflateInit(&un->un_stream); ++ if (unlikely(err == Z_MEM_ERROR)) ++ return -ENOMEM; ++ BUG_ON(err); ++ return err; ++} ++ ++void sqlzma_fin(struct sqlzma_un *un) ++{ ++ int i; ++ for (i = 0; i < SQUN_LAST; i++) ++ if (un->un_a[i].buf && un->un_a[i].buf != un->un_prob) ++ kfree(un->un_a[i].buf); ++ BUG_ON(zlib_inflateEnd(&un->un_stream) != Z_OK); ++} ++ ++#ifdef __KERNEL__ ++EXPORT_SYMBOL(sqlzma_un); ++EXPORT_SYMBOL(sqlzma_init); ++EXPORT_SYMBOL(sqlzma_fin); ++ ++#if 0 ++static int __init sqlzma_init(void) ++{ ++ return 0; ++} ++ ++static void __exit sqlzma_exit(void) ++{ ++} ++ ++module_init(sqlzma_init); ++module_exit(sqlzma_exit); ++#endif ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Junjiro Okajima <sfjro at users dot sf dot net>"); ++MODULE_VERSION("$Id: uncomp.c,v 1.1 2007/11/05 05:43:36 jro Exp $"); ++MODULE_DESCRIPTION("LZMA uncompress for squashfs. " ++ "Some functions for squashfs to support LZMA and " ++ "a tiny wrapper for LzmaDecode.c in LZMA SDK from www.7-zip.org."); ++#endif +diff -urN linux-2.6.23/include/linux/squashfs_fs.h linux-2.6.23.sqlzma-ng/include/linux/squashfs_fs.h +--- linux-2.6.23/include/linux/squashfs_fs.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/include/linux/squashfs_fs.h 2007-11-13 19:12:41.000000000 -0500 +@@ -0,0 +1,937 @@ ++#ifndef SQUASHFS_FS ++#define SQUASHFS_FS ++ ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher <phillip@lougher.demon.co.uk> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs.h ++ */ ++ ++#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++#define CONFIG_SQUASHFS_2_0_COMPATIBILITY ++#endif ++ ++#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE ++#define SQUASHFS_MAJOR 3 ++#define SQUASHFS_MINOR 1 ++#define SQUASHFS_MAGIC 0x73717368 ++#define SQUASHFS_MAGIC_SWAP 0x68737173 ++#define SQUASHFS_MAGIC_LZMA 0x71736873 ++#define SQUASHFS_MAGIC_LZMA_SWAP 0x73687371 ++#define SQUASHFS_START 0 ++ ++/* size of metadata (inode and directory) blocks */ ++#define SQUASHFS_METADATA_SIZE 8192 ++#define SQUASHFS_METADATA_LOG 13 ++ ++/* default size of data blocks */ ++#define SQUASHFS_FILE_SIZE 131072 ++#define SQUASHFS_FILE_LOG 17 ++ ++#define SQUASHFS_FILE_MAX_SIZE 1048576 ++ ++/* Max number of uids and gids */ ++#define SQUASHFS_UIDS 256 ++#define SQUASHFS_GUIDS 255 ++ ++/* Max length of filename (not 255) */ ++#define SQUASHFS_NAME_LEN 256 ++ ++#define SQUASHFS_INVALID ((long long) 0xffffffffffff) ++#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff) ++#define SQUASHFS_INVALID_BLK ((long long) -1) ++#define SQUASHFS_USED_BLK ((long long) -2) ++ ++/* Filesystem flags */ ++#define SQUASHFS_NOI 0 ++#define SQUASHFS_NOD 1 ++#define SQUASHFS_CHECK 2 ++#define SQUASHFS_NOF 3 ++#define SQUASHFS_NO_FRAG 4 ++#define SQUASHFS_ALWAYS_FRAG 5 ++#define SQUASHFS_DUPLICATE 6 ++#define SQUASHFS_EXPORT 7 ++ ++#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) ++ ++#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOI) ++ ++#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOD) ++ ++#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NOF) ++ ++#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_NO_FRAG) ++ ++#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_ALWAYS_FRAG) ++ ++#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_DUPLICATE) ++ ++#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_EXPORT) ++ ++#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \ ++ SQUASHFS_CHECK) ++ ++#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \ ++ duplicate_checking, exportable) (noi | (nod << 1) | (check_data << 2) \ ++ | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \ ++ (duplicate_checking << 6) | (exportable << 7)) ++ ++/* Max number of types and file types */ ++#define SQUASHFS_DIR_TYPE 1 ++#define SQUASHFS_FILE_TYPE 2 ++#define SQUASHFS_SYMLINK_TYPE 3 ++#define SQUASHFS_BLKDEV_TYPE 4 ++#define SQUASHFS_CHRDEV_TYPE 5 ++#define SQUASHFS_FIFO_TYPE 6 ++#define SQUASHFS_SOCKET_TYPE 7 ++#define SQUASHFS_LDIR_TYPE 8 ++#define SQUASHFS_LREG_TYPE 9 ++ ++/* 1.0 filesystem type definitions */ ++#define SQUASHFS_TYPES 5 ++#define SQUASHFS_IPC_TYPE 0 ++ ++/* Flag whether block is compressed or uncompressed, bit is set if block is ++ * uncompressed */ ++#define SQUASHFS_COMPRESSED_BIT (1 << 15) ++ ++#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ ++ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) ++ ++#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) ++ ++#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) ++ ++#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \ ++ ~SQUASHFS_COMPRESSED_BIT_BLOCK) ++ ++#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) ++ ++/* ++ * Inode number ops. Inodes consist of a compressed block number, and an ++ * uncompressed offset within that block ++ */ ++#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) ++ ++#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) ++ ++#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\ ++ << 16) + (B))) ++ ++/* Compute 32 bit VFS inode number from squashfs inode number */ ++#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \ ++ ((b) >> 2) + 1)) ++/* XXX */ ++ ++/* Translate between VFS mode and squashfs mode */ ++#define SQUASHFS_MODE(a) ((a) & 0xfff) ++ ++/* fragment and fragment table defines */ ++#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * sizeof(struct squashfs_fragment_entry)) ++ ++#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\ ++ sizeof(long long)) ++ ++/* inode lookup table defines */ ++#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode_t)) ++ ++#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\ ++ sizeof(long long)) ++ ++/* cached data constants for filesystem */ ++#define SQUASHFS_CACHED_BLKS 8 ++ ++#define SQUASHFS_MAX_FILE_SIZE_LOG 64 ++ ++#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \ ++ (SQUASHFS_MAX_FILE_SIZE_LOG - 2)) ++ ++#define SQUASHFS_MARKER_BYTE 0xff ++ ++/* meta index cache */ ++#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int)) ++#define SQUASHFS_META_ENTRIES 31 ++#define SQUASHFS_META_NUMBER 8 ++#define SQUASHFS_SLOTS 4 ++ ++struct meta_entry { ++ long long data_block; ++ unsigned int index_block; ++ unsigned short offset; ++ unsigned short pad; ++}; ++ ++struct meta_index { ++ unsigned int inode_number; ++ unsigned int offset; ++ unsigned short entries; ++ unsigned short skip; ++ unsigned short locked; ++ unsigned short pad; ++ struct meta_entry meta_entry[SQUASHFS_META_ENTRIES]; ++}; ++ ++ ++/* ++ * definitions for structures on disk ++ */ ++ ++typedef long long squashfs_block_t; ++typedef long long squashfs_inode_t; ++ ++struct squashfs_super_block { ++ unsigned int s_magic; ++ unsigned int inodes; ++ unsigned int bytes_used_2; ++ unsigned int uid_start_2; ++ unsigned int guid_start_2; ++ unsigned int inode_table_start_2; ++ unsigned int directory_table_start_2; ++ unsigned int s_major:16; ++ unsigned int s_minor:16; ++ unsigned int block_size_1:16; ++ unsigned int block_log:16; ++ unsigned int flags:8; ++ unsigned int no_uids:8; ++ unsigned int no_guids:8; ++ unsigned int mkfs_time /* time of filesystem creation */; ++ squashfs_inode_t root_inode; ++ unsigned int block_size; ++ unsigned int fragments; ++ unsigned int fragment_table_start_2; ++ long long bytes_used; ++ long long uid_start; ++ long long guid_start; ++ long long inode_table_start; ++ long long directory_table_start; ++ long long fragment_table_start; ++ long long lookup_table_start; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_index { ++ unsigned int index; ++ unsigned int start_block; ++ unsigned char size; ++ unsigned char name[0]; ++} __attribute__ ((packed)); ++ ++#define SQUASHFS_BASE_INODE_HEADER \ ++ unsigned int inode_type:4; \ ++ unsigned int mode:12; \ ++ unsigned int uid:8; \ ++ unsigned int guid:8; \ ++ unsigned int mtime; \ ++ unsigned int inode_number; ++ ++struct squashfs_base_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ squashfs_block_t start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ unsigned int file_size; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_lreg_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ squashfs_block_t start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ long long file_size; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int start_block; ++ unsigned int parent_inode; ++} __attribute__ ((packed)); ++ ++struct squashfs_ldir_inode_header { ++ SQUASHFS_BASE_INODE_HEADER; ++ unsigned int nlink; ++ unsigned int file_size:27; ++ unsigned int offset:13; ++ unsigned int start_block; ++ unsigned int i_count:16; ++ unsigned int parent_inode; ++ struct squashfs_dir_index index[0]; ++} __attribute__ ((packed)); ++ ++union squashfs_inode_header { ++ struct squashfs_base_inode_header base; ++ struct squashfs_dev_inode_header dev; ++ struct squashfs_symlink_inode_header symlink; ++ struct squashfs_reg_inode_header reg; ++ struct squashfs_lreg_inode_header lreg; ++ struct squashfs_dir_inode_header dir; ++ struct squashfs_ldir_inode_header ldir; ++ struct squashfs_ipc_inode_header ipc; ++}; ++ ++struct squashfs_dir_entry { ++ unsigned int offset:13; ++ unsigned int type:3; ++ unsigned int size:8; ++ unsigned int inode_number:16; ++ char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_header { ++ unsigned int count:8; ++ unsigned int start_block; ++ unsigned int inode_number; ++} __attribute__ ((packed)); ++ ++struct squashfs_fragment_entry { ++ long long start_block; ++ unsigned int size; ++ unsigned int pending; ++} __attribute__ ((packed)); ++ ++extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); ++extern int squashfs_uncompress_init(void); ++extern int squashfs_uncompress_exit(void); ++ ++/* ++ * macros to convert each packed bitfield structure from little endian to big ++ * endian and vice versa. These are needed when creating or using a filesystem ++ * on a machine with different byte ordering to the target architecture. ++ * ++ */ ++ ++#define SQUASHFS_SWAP_START \ ++ int bits;\ ++ int b_pos;\ ++ unsigned long long val;\ ++ unsigned char *s;\ ++ unsigned char *d; ++ ++#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\ ++ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\ ++ SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ ++ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ ++ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ ++ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\ ++ SQUASHFS_SWAP((s)->flags, d, 288, 8);\ ++ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\ ++ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\ ++ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\ ++ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ ++ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ ++ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ ++ SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\ ++ SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\ ++ SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\ ++ SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\ ++ SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\ ++ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\ ++ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\ ++ SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\ ++} ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ ++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 64, 32); ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_ipc_inode_header))\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_dev_inode_header)); \ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->rdev, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_reg_inode_header));\ ++ SQUASHFS_SWAP((s)->start_block, d, 96, 64);\ ++ SQUASHFS_SWAP((s)->fragment, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 224, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_lreg_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 128, 64);\ ++ SQUASHFS_SWAP((s)->fragment, d, 192, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 224, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 256, 64);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_dir_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 128, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 147, 13);\ ++ SQUASHFS_SWAP((s)->start_block, d, 160, 32);\ ++ SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ ++ sizeof(struct squashfs_ldir_inode_header));\ ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 128, 27);\ ++ SQUASHFS_SWAP((s)->offset, d, 155, 13);\ ++ SQUASHFS_SWAP((s)->start_block, d, 168, 32);\ ++ SQUASHFS_SWAP((s)->i_count, d, 200, 16);\ ++ SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\ ++ SQUASHFS_SWAP((s)->index, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->size, d, 64, 8);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\ ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\ ++ SQUASHFS_SWAP((s)->start_block, d, 8, 32);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\ ++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ ++ SQUASHFS_SWAP((s)->type, d, 13, 3);\ ++ SQUASHFS_SWAP((s)->size, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\ ++ SQUASHFS_SWAP((s)->start_block, d, 0, 64);\ ++ SQUASHFS_SWAP((s)->size, d, 64, 32);\ ++} ++ ++#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1) ++ ++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 2);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 16)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ ++} ++ ++#define SQUASHFS_SWAP_INTS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 4);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 32)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ ++} ++ ++#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * 8);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ 64)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, 64);\ ++} ++ ++#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ ++ int entry;\ ++ int bit_position;\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, n * bits / 8);\ ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ ++ bits)\ ++ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) ++#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) ++ ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY ++ ++struct squashfs_base_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int type:4; ++ unsigned int offset:4; ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int mtime; ++ unsigned int start_block; ++ unsigned int file_size:32; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header_1 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:4; /* index into uid table */ ++ unsigned int guid:4; /* index into guid table */ ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++union squashfs_inode_header_1 { ++ struct squashfs_base_inode_header_1 base; ++ struct squashfs_dev_inode_header_1 dev; ++ struct squashfs_symlink_inode_header_1 symlink; ++ struct squashfs_reg_inode_header_1 reg; ++ struct squashfs_dir_inode_header_1 dir; ++ struct squashfs_ipc_inode_header_1 ipc; ++}; ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 4);\ ++ SQUASHFS_SWAP((s)->guid, d, 20, 4); ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_ipc_inode_header_1));\ ++ SQUASHFS_SWAP((s)->type, d, 24, 4);\ ++ SQUASHFS_SWAP((s)->offset, d, 28, 4);\ ++} ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_dev_inode_header_1));\ ++ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header_1));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_reg_inode_header_1));\ ++ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 88, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ ++ sizeof(struct squashfs_dir_inode_header_1));\ ++ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 43, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ ++} ++ ++#endif ++ ++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY ++ ++struct squashfs_dir_index_2 { ++ unsigned int index:27; ++ unsigned int start_block:29; ++ unsigned char size; ++ unsigned char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_base_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_ipc_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++} __attribute__ ((packed)); ++ ++struct squashfs_dev_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned short rdev; ++} __attribute__ ((packed)); ++ ++struct squashfs_symlink_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned short symlink_size; ++ char symlink[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_reg_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int mtime; ++ unsigned int start_block; ++ unsigned int fragment; ++ unsigned int offset; ++ unsigned int file_size:32; ++ unsigned short block_list[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int file_size:19; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++struct squashfs_ldir_inode_header_2 { ++ unsigned int inode_type:4; ++ unsigned int mode:12; /* protection */ ++ unsigned int uid:8; /* index into uid table */ ++ unsigned int guid:8; /* index into guid table */ ++ unsigned int file_size:27; ++ unsigned int offset:13; ++ unsigned int mtime; ++ unsigned int start_block:24; ++ unsigned int i_count:16; ++ struct squashfs_dir_index_2 index[0]; ++} __attribute__ ((packed)); ++ ++union squashfs_inode_header_2 { ++ struct squashfs_base_inode_header_2 base; ++ struct squashfs_dev_inode_header_2 dev; ++ struct squashfs_symlink_inode_header_2 symlink; ++ struct squashfs_reg_inode_header_2 reg; ++ struct squashfs_dir_inode_header_2 dir; ++ struct squashfs_ldir_inode_header_2 ldir; ++ struct squashfs_ipc_inode_header_2 ipc; ++}; ++ ++struct squashfs_dir_header_2 { ++ unsigned int count:8; ++ unsigned int start_block:24; ++} __attribute__ ((packed)); ++ ++struct squashfs_dir_entry_2 { ++ unsigned int offset:13; ++ unsigned int type:3; ++ unsigned int size:8; ++ char name[0]; ++} __attribute__ ((packed)); ++ ++struct squashfs_fragment_entry_2 { ++ unsigned int start_block; ++ unsigned int size; ++} __attribute__ ((packed)); ++ ++#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ ++ SQUASHFS_MEMSET(s, d, n);\ ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ ++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ ++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ ++ ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ ++} ++ ++#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \ ++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2)) ++ ++#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_dev_inode_header_2)); \ ++ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_symlink_inode_header_2));\ ++ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ ++} ++ ++#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_reg_inode_header_2));\ ++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ ++ SQUASHFS_SWAP((s)->offset, d, 128, 32);\ ++ SQUASHFS_SWAP((s)->file_size, d, 160, 32);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_dir_inode_header_2));\ ++ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ ++ SQUASHFS_SWAP((s)->offset, d, 51, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ ++} ++ ++#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ ++ sizeof(struct squashfs_ldir_inode_header_2));\ ++ SQUASHFS_SWAP((s)->file_size, d, 32, 27);\ ++ SQUASHFS_SWAP((s)->offset, d, 59, 13);\ ++ SQUASHFS_SWAP((s)->mtime, d, 72, 32);\ ++ SQUASHFS_SWAP((s)->start_block, d, 104, 24);\ ++ SQUASHFS_SWAP((s)->i_count, d, 128, 16);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\ ++ SQUASHFS_SWAP((s)->index, d, 0, 27);\ ++ SQUASHFS_SWAP((s)->start_block, d, 27, 29);\ ++ SQUASHFS_SWAP((s)->size, d, 56, 8);\ ++} ++#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\ ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\ ++ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ ++} ++ ++#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\ ++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ ++ SQUASHFS_SWAP((s)->type, d, 13, 3);\ ++ SQUASHFS_SWAP((s)->size, d, 16, 8);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\ ++ SQUASHFS_SWAP_START\ ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\ ++ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ ++ SQUASHFS_SWAP((s)->size, d, 32, 32);\ ++} ++ ++#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) ++ ++/* fragment and fragment table defines */ ++#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2)) ++ ++#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \ ++ SQUASHFS_METADATA_SIZE - 1) / \ ++ SQUASHFS_METADATA_SIZE) ++ ++#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\ ++ sizeof(int)) ++ ++#endif ++ ++#ifdef __KERNEL__ ++ ++/* ++ * macros used to swap each structure entry, taking into account ++ * bitfields and different bitfield placing conventions on differing ++ * architectures ++ */ ++ ++#include <asm/byteorder.h> ++ ++#ifdef __BIG_ENDIAN ++ /* convert from little endian to big endian */ ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ ++ tbits, b_pos) ++#else ++ /* convert from big endian to little endian */ ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ ++ tbits, 64 - tbits - b_pos) ++#endif ++ ++#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ ++ b_pos = pos % 8;\ ++ val = 0;\ ++ s = (unsigned char *)p + (pos / 8);\ ++ d = ((unsigned char *) &val) + 7;\ ++ for(bits = 0; bits < (tbits + b_pos); bits += 8) \ ++ *d-- = *s++;\ ++ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ ++} ++ ++#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); ++ ++#endif ++#endif +diff -urN linux-2.6.23/include/linux/squashfs_fs_i.h linux-2.6.23.sqlzma-ng/include/linux/squashfs_fs_i.h +--- linux-2.6.23/include/linux/squashfs_fs_i.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/include/linux/squashfs_fs_i.h 2007-11-13 18:58:41.000000000 -0500 +@@ -0,0 +1,45 @@ ++#ifndef SQUASHFS_FS_I ++#define SQUASHFS_FS_I ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher <phillip@lougher.demon.co.uk> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs_i.h ++ */ ++ ++struct squashfs_inode_info { ++ long long start_block; ++ unsigned int offset; ++ union { ++ struct { ++ long long fragment_start_block; ++ unsigned int fragment_size; ++ unsigned int fragment_offset; ++ long long block_list_start; ++ } s1; ++ struct { ++ long long directory_index_start; ++ unsigned int directory_index_offset; ++ unsigned int directory_index_count; ++ unsigned int parent_inode; ++ } s2; ++ } u; ++ struct inode vfs_inode; ++}; ++#endif +diff -urN linux-2.6.23/include/linux/squashfs_fs_sb.h linux-2.6.23.sqlzma-ng/include/linux/squashfs_fs_sb.h +--- linux-2.6.23/include/linux/squashfs_fs_sb.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.23.sqlzma-ng/include/linux/squashfs_fs_sb.h 2007-11-13 19:19:28.000000000 -0500 +@@ -0,0 +1,76 @@ ++#ifndef SQUASHFS_FS_SB ++#define SQUASHFS_FS_SB ++/* ++ * Squashfs ++ * ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 ++ * Phillip Lougher <phillip@lougher.demon.co.uk> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2, ++ * or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * squashfs_fs_sb.h ++ */ ++ ++#include <linux/squashfs_fs.h> ++ ++struct squashfs_cache { ++ long long block; ++ int length; ++ long long next_index; ++ char *data; ++}; ++ ++struct squashfs_fragment_cache { ++ long long block; ++ int length; ++ unsigned int locked; ++ char *data; ++}; ++ ++struct squashfs_sb_info { ++ struct squashfs_super_block sblk; ++ int devblksize; ++ int devblksize_log2; ++ int swap; ++ struct squashfs_cache *block_cache; ++ struct squashfs_fragment_cache *fragment; ++ int next_cache; ++ int next_fragment; ++ int next_meta_index; ++ unsigned int *uid; ++ unsigned int *guid; ++ long long *fragment_index; ++ unsigned int *fragment_index_2; ++ char *read_page; ++ //struct mutex read_data_mutex; ++ struct mutex read_page_mutex; ++ struct mutex block_cache_mutex; ++ struct mutex fragment_mutex; ++ struct mutex meta_index_mutex; ++ wait_queue_head_t waitq; ++ wait_queue_head_t fragment_wait_queue; ++ struct meta_index *meta_index; ++ //z_stream stream; ++ long long *inode_lookup_table; ++ int unused_cache_blks; ++ int unused_frag_blks; ++ int (*read_inode)(struct inode *i, squashfs_inode_t \ ++ inode); ++ long long (*read_blocklist)(struct inode *inode, int \ ++ index, int readahead_blks, char *block_list, \ ++ unsigned short **block_p, unsigned int *bsize); ++ int (*read_fragment_index_table)(struct super_block *s); ++}; ++#endif + diff --git a/packages/linux/linux-openmoko-2.6.28/0002-squashfs-initrd.patch b/packages/linux/linux-openmoko-2.6.28/0002-squashfs-initrd.patch new file mode 100644 index 0000000000..cd2c678058 --- /dev/null +++ b/packages/linux/linux-openmoko-2.6.28/0002-squashfs-initrd.patch @@ -0,0 +1,55 @@ +diff -urN linux-2.6.23/init/do_mounts_rd.c linux-2.6.23.sqlzma-ng/init/do_mounts_rd.c +--- linux-2.6.23/init/do_mounts_rd.c 2007-10-09 16:31:38.000000000 -0400 ++++ linux-2.6.23.sqlzma-ng/init/do_mounts_rd.c 2007-11-13 18:58:41.000000000 -0500 +@@ -5,6 +5,7 @@ + #include <linux/ext2_fs.h> + #include <linux/romfs_fs.h> + #include <linux/cramfs_fs.h> ++#include <linux/squashfs_fs.h> + #include <linux/initrd.h> + #include <linux/string.h> + +@@ -39,6 +40,7 @@ + * numbers could not be found. + * + * We currently check for the following magic numbers: ++ * squashfs + * minix + * ext2 + * romfs +@@ -53,6 +55,7 @@ + struct ext2_super_block *ext2sb; + struct romfs_super_block *romfsb; + struct cramfs_super *cramfsb; ++ struct squashfs_super_block *squashfsb; + int nblocks = -1; + unsigned char *buf; + +@@ -64,6 +67,7 @@ + ext2sb = (struct ext2_super_block *) buf; + romfsb = (struct romfs_super_block *) buf; + cramfsb = (struct cramfs_super *) buf; ++ squashfsb = (struct squashfs_super_block *) buf; + memset(buf, 0xe5, size); + + /* +@@ -101,6 +105,18 @@ + goto done; + } + ++ /* squashfs is at block zero too */ ++ if (squashfsb->s_magic == SQUASHFS_MAGIC) { ++ printk(KERN_NOTICE ++ "RAMDISK: squashfs filesystem found at block %d\n", ++ start_block); ++ if (squashfsb->s_major < 3) ++ nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; ++ else ++ nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; ++ goto done; ++ } ++ + /* + * Read block 1 to test for minix and ext2 superblock + */ + diff --git a/packages/linux/linux-openmoko-2.6.28/0003-squashfs-force-O2.patch b/packages/linux/linux-openmoko-2.6.28/0003-squashfs-force-O2.patch new file mode 100644 index 0000000000..550077b9fa --- /dev/null +++ b/packages/linux/linux-openmoko-2.6.28/0003-squashfs-force-O2.patch @@ -0,0 +1,17 @@ +The kernel patch from the squashfs-3.1r2 release did not compile on my +armeb-linux-gcc 4.1.1 when optimizing for size (-Os). This works around +that problem by using optimization flag -O2 instead for these two files. + +Signed-off-by: Leon Woestenberg <leonw@mailcan.com> + +Index: linux-2.6.19/fs/squashfs/Makefile +=================================================================== +--- linux-2.6.19.orig/fs/squashfs/Makefile ++++ linux-2.6.19/fs/squashfs/Makefile +@@ -5,3 +5,6 @@ + obj-$(CONFIG_SQUASHFS) += squashfs.o + squashfs-y += inode.o + squashfs-y += squashfs2_0.o ++ ++CFLAGS_squashfs2_0.o = "-O2" ++CFLAGS_inode.o = "-O2" diff --git a/packages/linux/linux-openmoko-2.6.28/0004-squashfs-Kconfig.patch b/packages/linux/linux-openmoko-2.6.28/0004-squashfs-Kconfig.patch new file mode 100644 index 0000000000..f2b3db9942 --- /dev/null +++ b/packages/linux/linux-openmoko-2.6.28/0004-squashfs-Kconfig.patch @@ -0,0 +1,61 @@ +diff -urN linux-2.6.23/fs/Kconfig linux-2.6.23.sqlzma-ng/fs/Kconfig +--- linux-2.6.23/fs/Kconfig 2007-10-09 16:31:38.000000000 -0400 ++++ linux-2.6.23.sqlzma-ng/fs/Kconfig 2007-11-13 18:58:41.000000000 -0500 +@@ -1364,6 +1364,56 @@ + + If unsure, say N. + ++config SQUASHFS ++ tristate "SquashFS 3.3 - Squashed file system support" ++ select ZLIB_INFLATE ++ help ++ Saying Y here includes support for SquashFS 3.3 (a Compressed ++ Read-Only File System). Squashfs is a highly compressed read-only ++ filesystem for Linux. It uses zlib compression to compress both ++ files, inodes and directories. Inodes in the system are very small ++ and all blocks are packed to minimise data overhead. Block sizes ++ greater than 4K are supported up to a maximum of 1 Mbytes (default ++ block size 128K). SquashFS 3.3 supports 64 bit filesystems and files ++ (larger than 4GB), full uid/gid information, hard links and timestamps. ++ ++ Squashfs is intended for general read-only filesystem use, for ++ archival use (i.e. in cases where a .tar.gz file may be used), and in ++ embedded systems where low overhead is needed. Further information ++ and filesystem tools are available from http://squashfs.sourceforge.net. ++ ++ If you want to compile this as a module ( = code which can be ++ inserted in and removed from the running kernel whenever you want), ++ say M here and read <file:Documentation/modules.txt>. The module ++ will be called squashfs. Note that the root file system (the one ++ containing the directory /) cannot be compiled as a module. ++ ++ If unsure, say N. ++ ++config SQUASHFS_EMBEDDED ++ ++ bool "Additional option for memory-constrained systems" ++ depends on SQUASHFS ++ default n ++ help ++ Saying Y here allows you to specify cache size. ++ ++ If unsure, say N. ++ ++config SQUASHFS_FRAGMENT_CACHE_SIZE ++ int "Number of fragments cached" if SQUASHFS_EMBEDDED ++ depends on SQUASHFS ++ default "3" ++ help ++ By default SquashFS caches the last 3 fragments read from ++ the filesystem. Increasing this amount may mean SquashFS ++ has to re-read fragments less often from disk, at the expense ++ of extra system memory. Decreasing this amount will mean ++ SquashFS uses less memory at the expense of extra reads from disk. ++ ++ Note there must be at least one cached fragment. Anything ++ much more than three will probably not make much difference. ++ + config VXFS_FS + tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" + depends on BLOCK + diff --git a/packages/linux/linux-openmoko-2.6.28/0005-squashfs-Makefile.patch b/packages/linux/linux-openmoko-2.6.28/0005-squashfs-Makefile.patch new file mode 100644 index 0000000000..b0ec4cebb8 --- /dev/null +++ b/packages/linux/linux-openmoko-2.6.28/0005-squashfs-Makefile.patch @@ -0,0 +1,12 @@ +diff -urN linux-2.6.24/fs/Makefile linux-2.6.24.sqlzma-ng/fs/Makefile +--- linux-2.6.24/fs/Makefile 2007-11-13 21:24:14.000000000 -0500 ++++ linux-2.6.24.sqlzma-ng/fs/Makefile 2007-11-13 21:19:15.000000000 -0500 +@@ -72,6 +72,7 @@ + obj-$(CONFIG_JBD2) += jbd2/ + obj-$(CONFIG_EXT2_FS) += ext2/ + obj-$(CONFIG_CRAMFS) += cramfs/ ++obj-$(CONFIG_SQUASHFS) += squashfs/ + obj-y += ramfs/ + obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ + obj-$(CONFIG_CODA_FS) += coda/ + diff --git a/packages/linux/linux-openmoko-2.6.28/defconfig-oe.patch b/packages/linux/linux-openmoko-2.6.28/defconfig-oe.patch new file mode 100644 index 0000000000..0014f12cc0 --- /dev/null +++ b/packages/linux/linux-openmoko-2.6.28/defconfig-oe.patch @@ -0,0 +1,39 @@ +Index: defconfig-oe +=================================================================== +--- defconfig-oe 2008-12-31 18:54:08.000000000 +0100 ++++ defconfig-oe 2008-12-20 22:24:39.000000000 +0100 +@@ -337,9 +337,6 @@ + # + # At least one emulation must be selected + # +-CONFIG_FPE_NWFPE=y +-# CONFIG_FPE_NWFPE_XP is not set +-# CONFIG_FPE_FASTFPE is not set + + # + # Userspace binary formats +@@ -1640,9 +1635,10 @@ + # + CONFIG_LEDS_TRIGGERS=y + CONFIG_LEDS_TRIGGER_TIMER=y +-# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set ++CONFIG_LEDS_TRIGGER_HEARTBEAT=y + CONFIG_LEDS_TRIGGER_BACKLIGHT=y + # CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set ++CONFIG_LEDS_TRIGGER_NETDEV=y + CONFIG_RTC_LIB=y + CONFIG_RTC_CLASS=y + CONFIG_RTC_HCTOSYS=y +@@ -1827,7 +1823,11 @@ + # CONFIG_SYSV_FS is not set + # CONFIG_UFS_FS is not set + CONFIG_NETWORK_FILESYSTEMS=y +-# CONFIG_NFS_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NFS_V3_ACL=y ++# CONFIG_NFS_V4 is not set ++CONFIG_ROOT_NFS=y + CONFIG_NFSD=y + CONFIG_NFSD_V2_ACL=y + CONFIG_NFSD_V3=y diff --git a/packages/linux/linux-openmoko-2.6.28/openwrt-ledtrig-netdev.patch b/packages/linux/linux-openmoko-2.6.28/openwrt-ledtrig-netdev.patch new file mode 100644 index 0000000000..e87bccce61 --- /dev/null +++ b/packages/linux/linux-openmoko-2.6.28/openwrt-ledtrig-netdev.patch @@ -0,0 +1,474 @@ +Add a netdev LED trigger for all Blinkenlights lovers... +Originally taken from https://dev.openwrt.org/ticket/2776 +Slightly updated for 2.6.24 by Mickey <mickey@openmoko.org>. + +Index: git/drivers/leds/ledtrig-netdev.c +=================================================================== +--- /dev/null ++++ git/drivers/leds/ledtrig-netdev.c +@@ -0,0 +1,438 @@ ++/* ++ * LED Kernel Netdev Trigger ++ * ++ * Toggles the LED to reflect the link and traffic state of a named net device ++ * ++ * Copyright 2007 Oliver Jowett <oliver@opencloud.com> ++ * ++ * Derived from ledtrig-timer.c which is: ++ * Copyright 2005-2006 Openedhand Ltd. ++ * Author: Richard Purdie <rpurdie@openedhand.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/jiffies.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/list.h> ++#include <linux/spinlock.h> ++#include <linux/device.h> ++#include <linux/sysdev.h> ++#include <linux/netdevice.h> ++#include <linux/timer.h> ++#include <linux/ctype.h> ++#include <linux/leds.h> ++#include "leds.h" ++ ++/* ++ * Configurable sysfs attributes: ++ * ++ * device_name - network device name to monitor ++ * ++ * interval - duration of LED blink, in milliseconds ++ * ++ * mode - either "none" (LED is off) or a space separated list of one or more of: ++ * link: LED's normal state reflects whether the link is up (has carrier) or not ++ * tx: LED blinks on transmitted data ++ * rx: LED blinks on receive data ++ * ++ * Some suggestions: ++ * ++ * Simple link status LED: ++ * $ echo netdev >someled/trigger ++ * $ echo eth0 >someled/device_name ++ * $ echo link >someled/mode ++ * ++ * Ethernet-style link/activity LED: ++ * $ echo netdev >someled/trigger ++ * $ echo eth0 >someled/device_name ++ * $ echo "link tx rx" >someled/mode ++ * ++ * Modem-style tx/rx LEDs: ++ * $ echo netdev >led1/trigger ++ * $ echo ppp0 >led1/device_name ++ * $ echo tx >led1/mode ++ * $ echo netdev >led2/trigger ++ * $ echo ppp0 >led2/device_name ++ * $ echo rx >led2/mode ++ * ++ */ ++ ++#define MODE_LINK 1 ++#define MODE_TX 2 ++#define MODE_RX 4 ++ ++struct led_netdev_data { ++ rwlock_t lock; ++ ++ struct timer_list timer; ++ struct notifier_block notifier; ++ ++ struct led_classdev *led_cdev; ++ struct net_device *net_dev; ++ ++ char device_name[IFNAMSIZ]; ++ unsigned interval; ++ unsigned mode; ++ unsigned link_up; ++ unsigned last_activity; ++}; ++ ++static void set_baseline_state(struct led_netdev_data *trigger_data) ++{ ++ if ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ++ led_set_brightness(trigger_data->led_cdev, LED_FULL); ++ else ++ led_set_brightness(trigger_data->led_cdev, LED_OFF); ++ ++ if ((trigger_data->mode & (MODE_TX | MODE_RX)) != 0 && trigger_data->link_up) ++ mod_timer(&trigger_data->timer, jiffies + trigger_data->interval); ++ else ++ del_timer(&trigger_data->timer); ++} ++ ++static ssize_t led_device_name_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ ++ read_lock(&trigger_data->lock); ++ sprintf(buf, "%s\n", trigger_data->device_name); ++ read_unlock(&trigger_data->lock); ++ ++ return strlen(buf) + 1; ++} ++ ++static ssize_t led_device_name_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ ++ if (size < 0 || size >= IFNAMSIZ) ++ return -EINVAL; ++ ++ write_lock(&trigger_data->lock); ++ ++ strcpy(trigger_data->device_name, buf); ++ if (size > 0 && trigger_data->device_name[size-1] == '\n') ++ trigger_data->device_name[size-1] = 0; ++ ++ if (trigger_data->device_name[0] != 0) { ++ /* check for existing device to update from */ ++ trigger_data->net_dev = dev_get_by_name(&init_net, trigger_data->device_name); ++ if (trigger_data->net_dev != NULL) ++ trigger_data->link_up = (dev_get_flags(trigger_data->net_dev) & IFF_LOWER_UP) != 0; ++ set_baseline_state(trigger_data); /* updates LEDs, may start timers */ ++ } ++ ++ write_unlock(&trigger_data->lock); ++ return size; ++} ++ ++static DEVICE_ATTR(device_name, 0644, led_device_name_show, led_device_name_store); ++ ++static ssize_t led_mode_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ ++ read_lock(&trigger_data->lock); ++ ++ if (trigger_data->mode == 0) { ++ strcpy(buf, "none\n"); ++ } else { ++ char *p = buf; ++ if (trigger_data->mode & MODE_LINK) ++ strcat(buf, "link "); ++ if (trigger_data->mode & MODE_TX) ++ strcat(buf, "tx "); ++ if (trigger_data->mode & MODE_RX) ++ strcat(buf, "rx "); ++ strcat(buf, "\n"); ++ } ++ ++ read_unlock(&trigger_data->lock); ++ ++ return strlen(buf)+1; ++} ++ ++static ssize_t led_mode_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ char copybuf[1024]; ++ int new_mode = -1; ++ char *p, *token; ++ ++ /* take a copy since we don't want to trash the inbound buffer when using strsep */ ++ strncpy(copybuf, buf, sizeof(copybuf)); ++ copybuf[1023] = 0; ++ p = copybuf; ++ ++ while ((token = strsep(&p, " \t\n")) != NULL) { ++ if (!*token) ++ continue; ++ ++ if (new_mode == -1) ++ new_mode = 0; ++ ++ if (!strcmp(token, "none")) ++ new_mode = 0; ++ else if (!strcmp(token, "tx")) ++ new_mode |= MODE_TX; ++ else if (!strcmp(token, "rx")) ++ new_mode |= MODE_RX; ++ else if (!strcmp(token, "link")) ++ new_mode |= MODE_LINK; ++ else ++ return -EINVAL; ++ } ++ ++ if (new_mode == -1) ++ return -EINVAL; ++ ++ write_lock(&trigger_data->lock); ++ trigger_data->mode = new_mode; ++ set_baseline_state(trigger_data); ++ write_unlock(&trigger_data->lock); ++ ++ return size; ++} ++ ++static DEVICE_ATTR(mode, 0644, led_mode_show, led_mode_store); ++ ++static ssize_t led_interval_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ ++ read_lock(&trigger_data->lock); ++ sprintf(buf, "%u\n", jiffies_to_msecs(trigger_data->interval)); ++ read_unlock(&trigger_data->lock); ++ ++ return strlen(buf) + 1; ++} ++ ++static ssize_t led_interval_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t size) ++{ ++ struct led_classdev *led_cdev = dev_get_drvdata(dev); ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ int ret = -EINVAL; ++ char *after; ++ unsigned long value = simple_strtoul(buf, &after, 10); ++ size_t count = after - buf; ++ ++ if (*after && isspace(*after)) ++ count++; ++ ++ /* impose some basic bounds on the timer interval */ ++ if (count == size && value >= 5 && value <= 10000) { ++ write_lock(&trigger_data->lock); ++ trigger_data->interval = msecs_to_jiffies(value); ++ set_baseline_state(trigger_data); // resets timer ++ write_unlock(&trigger_data->lock); ++ ret = count; ++ } ++ ++ return ret; ++} ++ ++static DEVICE_ATTR(interval, 0644, led_interval_show, led_interval_store); ++ ++static int netdev_trig_notify(struct notifier_block *nb, ++ unsigned long evt, ++ void *dv) ++{ ++ struct net_device *dev = dv; ++ struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier); ++ ++ if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER) ++ return NOTIFY_DONE; ++ ++ write_lock(&trigger_data->lock); ++ ++ if (strcmp(dev->name, trigger_data->device_name)) ++ goto done; ++ ++ if (evt == NETDEV_REGISTER) { ++ if (trigger_data->net_dev != NULL) ++ dev_put(trigger_data->net_dev); ++ dev_hold(dev); ++ trigger_data->net_dev = dev; ++ trigger_data->link_up = 0; ++ goto done; ++ } ++ ++ if (evt == NETDEV_UNREGISTER && trigger_data->net_dev != NULL) { ++ dev_put(trigger_data->net_dev); ++ trigger_data->net_dev = NULL; ++ goto done; ++ } ++ ++ /* UP / DOWN / CHANGE */ ++ ++ trigger_data->link_up = (evt != NETDEV_DOWN && netif_carrier_ok(dev)); ++ set_baseline_state(trigger_data); ++ ++done: ++ write_unlock(&trigger_data->lock); ++ return NOTIFY_DONE; ++} ++ ++/* here's the real work! */ ++static void netdev_trig_timer(unsigned long arg) ++{ ++ struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg; ++ struct net_device_stats *dev_stats; ++ unsigned new_activity; ++ ++ write_lock(&trigger_data->lock); ++ ++ if (!trigger_data->link_up || !trigger_data->net_dev || (trigger_data->mode & (MODE_TX | MODE_RX)) == 0) { ++ /* we don't need to do timer work, just reflect link state. */ ++ led_set_brightness(trigger_data->led_cdev, ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ? LED_FULL : LED_OFF); ++ goto no_restart; ++ } ++ ++ dev_stats = trigger_data->net_dev->get_stats(trigger_data->net_dev); ++ new_activity = ++ ((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) + ++ ((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0); ++ ++ if (trigger_data->mode & MODE_LINK) { ++ /* base state is ON (link present) */ ++ /* if there's no link, we don't get this far and the LED is off */ ++ ++ /* OFF -> ON always */ ++ /* ON -> OFF on activity */ ++ if (trigger_data->led_cdev->brightness == LED_OFF) { ++ led_set_brightness(trigger_data->led_cdev, LED_FULL); ++ } else if (trigger_data->last_activity != new_activity) { ++ led_set_brightness(trigger_data->led_cdev, LED_OFF); ++ } ++ } else { ++ /* base state is OFF */ ++ /* ON -> OFF always */ ++ /* OFF -> ON on activity */ ++ if (trigger_data->led_cdev->brightness == LED_FULL) { ++ led_set_brightness(trigger_data->led_cdev, LED_OFF); ++ } else if (trigger_data->last_activity != new_activity) { ++ led_set_brightness(trigger_data->led_cdev, LED_FULL); ++ } ++ } ++ ++ trigger_data->last_activity = new_activity; ++ mod_timer(&trigger_data->timer, jiffies + trigger_data->interval); ++ ++no_restart: ++ write_unlock(&trigger_data->lock); ++} ++ ++static void netdev_trig_activate(struct led_classdev *led_cdev) ++{ ++ struct led_netdev_data *trigger_data; ++ int rc; ++ ++ trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL); ++ if (!trigger_data) ++ return; ++ ++ rwlock_init(&trigger_data->lock); ++ ++ trigger_data->notifier.notifier_call = netdev_trig_notify; ++ trigger_data->notifier.priority = 10; ++ ++ setup_timer(&trigger_data->timer, netdev_trig_timer, (unsigned long) trigger_data); ++ ++ trigger_data->led_cdev = led_cdev; ++ trigger_data->net_dev = NULL; ++ trigger_data->device_name[0] = 0; ++ ++ trigger_data->mode = 0; ++ trigger_data->interval = msecs_to_jiffies(50); ++ trigger_data->link_up = 0; ++ trigger_data->last_activity = 0; ++ ++ led_cdev->trigger_data = trigger_data; ++ ++ rc = device_create_file(led_cdev->dev, &dev_attr_device_name); ++ if (rc) ++ goto err_out; ++ rc = device_create_file(led_cdev->dev, &dev_attr_mode); ++ if (rc) ++ goto err_out_device_name; ++ rc = device_create_file(led_cdev->dev, &dev_attr_interval); ++ if (rc) ++ goto err_out_mode; ++ ++ register_netdevice_notifier(&trigger_data->notifier); ++ return; ++ ++err_out_mode: ++ device_remove_file(led_cdev->dev, &dev_attr_mode); ++err_out_device_name: ++ device_remove_file(led_cdev->dev, &dev_attr_device_name); ++err_out: ++ led_cdev->trigger_data = NULL; ++ kfree(trigger_data); ++} ++ ++static void netdev_trig_deactivate(struct led_classdev *led_cdev) ++{ ++ struct led_netdev_data *trigger_data = led_cdev->trigger_data; ++ ++ if (trigger_data) { ++ unregister_netdevice_notifier(&trigger_data->notifier); ++ ++ device_remove_file(led_cdev->dev, &dev_attr_device_name); ++ device_remove_file(led_cdev->dev, &dev_attr_mode); ++ device_remove_file(led_cdev->dev, &dev_attr_interval); ++ ++ write_lock(&trigger_data->lock); ++ ++ if (trigger_data->net_dev) { ++ dev_put(trigger_data->net_dev); ++ trigger_data->net_dev = NULL; ++ } ++ ++ write_unlock(&trigger_data->lock); ++ ++ del_timer_sync(&trigger_data->timer); ++ ++ kfree(trigger_data); ++ } ++} ++ ++static struct led_trigger netdev_led_trigger = { ++ .name = "netdev", ++ .activate = netdev_trig_activate, ++ .deactivate = netdev_trig_deactivate, ++}; ++ ++static int __init netdev_trig_init(void) ++{ ++ return led_trigger_register(&netdev_led_trigger); ++} ++ ++static void __exit netdev_trig_exit(void) ++{ ++ led_trigger_unregister(&netdev_led_trigger); ++} ++ ++module_init(netdev_trig_init); ++module_exit(netdev_trig_exit); ++ ++MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>"); ++MODULE_DESCRIPTION("Netdev LED trigger"); ++MODULE_LICENSE("GPL"); +Index: git/drivers/leds/Kconfig +=================================================================== +--- git.orig/drivers/leds/Kconfig ++++ git/drivers/leds/Kconfig +@@ -229,4 +229,11 @@ config LEDS_TRIGGER_DEFAULT_ON + This allows LEDs to be initialised in the ON state. + If unsure, say Y. + ++config LEDS_TRIGGER_NETDEV ++ tristate "LED Network Device Trigger" ++ depends on LEDS_TRIGGERS ++ help ++ This allows LEDs to be controlled by Network Device activity. ++ If unsure, say Y. ++ + endif # NEW_LEDS +Index: git/drivers/leds/Makefile +=================================================================== +--- git.orig/drivers/leds/Makefile ++++ git/drivers/leds/Makefile +@@ -30,5 +30,6 @@ obj-$(CONFIG_LEDS_NEO1973_GTA02) += leds + obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o + obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o + obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o ++obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o + obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o + obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o diff --git a/packages/linux/linux-openmoko_2.6.24+git.bb b/packages/linux/linux-openmoko_2.6.24+git.bb index 2010d1d02a..946dfa8167 100644 --- a/packages/linux/linux-openmoko_2.6.24+git.bb +++ b/packages/linux/linux-openmoko_2.6.24+git.bb @@ -6,7 +6,9 @@ DESCRIPTION = "The Linux kernel for the Openmoko devices GTA01 (Neo1973) and GTA KERNEL_RELEASE = "2.6.24" KERNEL_VERSION = "${KERNEL_RELEASE}" -OEV = "oe4" +# fixed SRCREV, this kernel is EOL +SRCREV = "fb42ce6724576fc173faf8abfb04aa2c36d213b7" +OEV = "oe5" PV = "${KERNEL_RELEASE}-${OEV}+gitr${SRCREV}" PR = "r0" diff --git a/packages/linux/linux-openmoko_2.6.28+git.bb b/packages/linux/linux-openmoko_2.6.28+git.bb new file mode 100644 index 0000000000..a544b89f13 --- /dev/null +++ b/packages/linux/linux-openmoko_2.6.28+git.bb @@ -0,0 +1,26 @@ +require linux.inc +require linux-openmoko.inc + +DESCRIPTION_${PN} = "Linux ${KERNEL_RELEASE} kernel for the Openmoko Neo GSM Smartphones" + +KERNEL_RELEASE = "2.6.28" +KERNEL_VERSION = "${KERNEL_RELEASE}" + +FILESPATH = "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/linux-openmoko-${KERNEL_RELEASE}" + +OEV = "oe1" +PV = "${KERNEL_RELEASE}-${OEV}+gitr${SRCREV}" +PR = "r0" + +SRC_URI = "\ + git://git.openmoko.org/git/kernel.git;protocol=git;branch=andy-tracking \ + file://openwrt-ledtrig-netdev.patch;patch=1 \ + file://defconfig-oe.patch \ +" +S = "${WORKDIR}/git" + +do_configure_prepend() { + install -m 644 ./arch/arm/configs/gta02-moredrivers-defconfig ${WORKDIR}/defconfig-oe + cat ${WORKDIR}/defconfig-oe.patch | patch -p0 -d ${WORKDIR} +} + |