Opera 12.15 Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BlockStorage.cpp 74KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988
  1. /* -*- Mode: c++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
  2. **
  3. ** Copyright (C) 1995-2011 Opera Software ASA. All rights reserved.
  4. **
  5. ** This file is part of the Opera web browser.
  6. ** It may not be distributed under any circumstances.
  7. */
  8. #include "core/pch.h"
  9. #ifdef SEARCH_ENGINE // to remove compilation errors with ADVANCED_OPVECTOR
  10. #include "modules/pi/system/OpFolderLister.h"
  11. #include "modules/search_engine/BlockStorage.h"
  12. #include "modules/search_engine/BufferedLowLevelFile.h"
  13. #include "modules/search_engine/ExponentialGrowthFile.h"
  14. // To evaluate memory usage when we don't buffer BlockStorage,
  15. // enable this define:
  16. #undef DONT_BUFFER_BLOCK_STORAGE
  17. #define OLD_JOURNAL_FILE_HEADER 0xBBFF0200
  18. #define OLD_JOURNAL_FILE_HEADER_I 0x0002FFBB
  19. #define BLOCK_FILE_HEADER_0201 0xBBFF0201
  20. #define BLOCK_FILE_HEADER_0201_I 0x0102FFBB
  21. #define BLOCK_FILE_HEADER_0202 0xBBFF0202
  22. #define BLOCK_FILE_HEADER_0202_I 0x0202FFBB
  23. #define BLOCK_FILE_HEADER 0xBBFF0203
  24. #define BLOCK_FILE_HEADER_I 0x0302FFBB
  25. // size of a file header
  26. #define FILE_HDR_SIZE 16
  27. // size of a block header
  28. #define BLOCK_HDR_SIZE 8
  29. // size of journal header
  30. #define JOURNAL_HDR_SIZE 8
  31. #define TRANSACTION_NAME_SUFFIX UNI_L("-j")
  32. #define INVALID_JOURNAL_SUFFIX UNI_L("-g")
  33. #define ATOMIC_COMMIT_IN_PROGRESS_SUFFIX UNI_L("-d")
  34. #define RETURN_IF_ERROR_CLEANUP( expr ) do { if (OpStatus::IsError(rv = expr)) goto cleanup; } while (0);
  35. #define DISTANCE_BETWEEN_BITFIELDS ((OpFileLength)m_blocksize * 8 * m_blocksize + m_blocksize)
  36. #define DISTANCE_BEHIND_BITFIELD(pos) (((pos) - m_blocksize) % DISTANCE_BETWEEN_BITFIELDS)
  37. #define BITFIELD_POS(pos) ((pos) - DISTANCE_BEHIND_BITFIELD(pos))
  38. #define IS_BITFIELD_BLOCK(pos) (DISTANCE_BEHIND_BITFIELD(pos) == 0)
  39. #define AT_BLOCK_BOUNDARY(pos) ((pos) % m_blocksize == 0)
  40. #define IS_NORMAL_BLOCK(pos) (pos != 0 && AT_BLOCK_BOUNDARY(pos) && !IS_BITFIELD_BLOCK(pos))
  41. #ifdef _DEBUG
  42. #define IS_START_BLOCK(pos) (IS_NORMAL_BLOCK(pos) && (!m_start_blocks_supported || IsStartBlock(pos)))
  43. #else
  44. #define IS_START_BLOCK(pos) IS_NORMAL_BLOCK(pos)
  45. #endif
  46. #define IS_NOT_START_BLOCK(pos) (pos == 0 || (IS_NORMAL_BLOCK(pos) && (!m_start_blocks_supported || !IsStartBlock(pos))))
  47. #define SWAP_UINT32(a) ((((a) & 0x000000ffU)<<24) + (((a) & 0x0000ff00U)<< 8) + \
  48. (((a) & 0x00ff0000U)>> 8) + (((a) & 0xff000000U)>>24))
  49. #ifdef HAVE_UINT64
  50. #define ANY_INT64 UINT64
  51. #elif defined HAVE_INT64
  52. #define ANY_INT64 INT64
  53. #else
  54. #undef ANY_INT64
  55. #endif
  56. static OpFileLength SWAP_OFL(OpFileLength i)
  57. {
  58. OpFileLength tmp_i;
  59. unsigned char *src = (unsigned char *)&i;
  60. unsigned char *dst = (unsigned char *)&tmp_i + sizeof(OpFileLength);
  61. int j;
  62. for (j = 0; j < (int)sizeof(OpFileLength); ++j)
  63. *--dst = *src++;
  64. return tmp_i;
  65. }
  66. OP_STATUS BlockStorage::ReadFully(OpLowLevelFile *f, void* data, OpFileLength len)
  67. {
  68. OpFileLength bytes_read;
  69. while (len > 0) {
  70. RETURN_IF_ERROR(f->Read(data, len, &bytes_read));
  71. if (bytes_read == 0)
  72. return OpStatus::ERR_OUT_OF_RANGE; // File too short
  73. len -= bytes_read;
  74. data = (void*)((char*)data + bytes_read);
  75. }
  76. return OpStatus::OK;
  77. }
  78. static OP_STATUS ReadInt32Straight(OpLowLevelFile *f, INT32 *i)
  79. {
  80. return BlockStorage::ReadFully(f, i, 4);
  81. }
  82. static OP_STATUS WriteInt32Straight(OpLowLevelFile *f, INT32 i)
  83. {
  84. return f->Write(&i, 4);
  85. }
  86. static OP_STATUS ReadInt32Swap(OpLowLevelFile *f, INT32 *i)
  87. {
  88. UINT32 tmp_i;
  89. RETURN_IF_ERROR(BlockStorage::ReadFully(f, &tmp_i, 4));
  90. *i = (INT32)SWAP_UINT32(tmp_i);
  91. return OpStatus::OK;
  92. }
  93. static OP_STATUS WriteInt32Swap(OpLowLevelFile *f, INT32 i)
  94. {
  95. i = (UINT32) SWAP_UINT32((UINT32) i);
  96. return f->Write(&i, 4);
  97. }
  98. static OP_STATUS ReadInt64Straight(OpLowLevelFile *f, OpFileLength *i, UINT32 *msb32)
  99. {
  100. UINT32 tmp_i;
  101. #ifdef ANY_INT64
  102. if (sizeof(OpFileLength) == 8) {
  103. RETURN_IF_ERROR(BlockStorage::ReadFully(f, i, 8));
  104. if (msb32 != NULL)
  105. *msb32 = (UINT32)((ANY_INT64)*i >> 32);
  106. return OpStatus::OK;
  107. }
  108. #else
  109. OP_ASSERT(sizeof(OpFileLength) == 4);
  110. #endif
  111. if (msb32 == NULL)
  112. msb32 = &tmp_i;
  113. #ifndef OPERA_BIG_ENDIAN
  114. RETURN_IF_ERROR(BlockStorage::ReadFully(f, i, 4));
  115. return BlockStorage::ReadFully(f, msb32, 4);
  116. #else
  117. RETURN_IF_ERROR(BlockStorage::ReadFully(f, msb32, 4));
  118. return BlockStorage::ReadFully(f, i, 4);
  119. #endif
  120. }
  121. static OP_STATUS WriteInt64Straight(OpLowLevelFile *f, OpFileLength i, UINT32 msb32)
  122. {
  123. #ifdef ANY_INT64
  124. if (sizeof(OpFileLength) == 8) {
  125. if (msb32 != 0)
  126. i |= (OpFileLength)((ANY_INT64)msb32 << 32);
  127. return f->Write(&i, 8);
  128. }
  129. #else
  130. OP_ASSERT(sizeof(OpFileLength) == 4);
  131. #endif
  132. #ifndef OPERA_BIG_ENDIAN
  133. RETURN_IF_ERROR(f->Write(&i, 4));
  134. return f->Write(&msb32, 4);
  135. #else
  136. RETURN_IF_ERROR(f->Write(&msb32, 4));
  137. return f->Write(&i, 4);
  138. #endif
  139. }
  140. static OP_STATUS ReadInt64Swap(OpLowLevelFile *f, OpFileLength *i, UINT32 *msb32)
  141. {
  142. UINT32 tmp_i;
  143. OpFileLength tmp;
  144. #ifdef ANY_INT64
  145. if (sizeof(OpFileLength) == 8) {
  146. RETURN_IF_ERROR(BlockStorage::ReadFully(f, &tmp, 8));
  147. tmp = SWAP_OFL(tmp);
  148. *i = tmp;
  149. if (msb32 != NULL)
  150. *msb32 = (UINT32)((ANY_INT64)tmp >> 32);
  151. return OpStatus::OK;
  152. }
  153. #else
  154. OP_ASSERT(sizeof(OpFileLength) == 4);
  155. #endif
  156. if (msb32 == NULL)
  157. msb32 = &tmp_i;
  158. #ifndef OPERA_BIG_ENDIAN
  159. RETURN_IF_ERROR(ReadInt32Swap(f, (INT32*)msb32));
  160. return ReadInt32Swap(f, (INT32*)i);
  161. #else
  162. RETURN_IF_ERROR(ReadInt32Swap(f, (INT32*)i));
  163. return ReadInt32Swap(f, (INT32*)msb32);
  164. #endif
  165. }
  166. static OP_STATUS WriteInt64Swap(OpLowLevelFile *f, OpFileLength i, UINT32 msb32)
  167. {
  168. #ifdef ANY_INT64
  169. if (sizeof(OpFileLength) == 8) {
  170. if (msb32 != 0)
  171. i |= (OpFileLength)((ANY_INT64)msb32 << 32);
  172. i = SWAP_OFL(i);
  173. return f->Write(&i, 8);
  174. }
  175. #else
  176. OP_ASSERT(sizeof(OpFileLength) == 4);
  177. #endif
  178. #ifndef OPERA_BIG_ENDIAN
  179. RETURN_IF_ERROR(WriteInt32Swap(f, (INT32)msb32));
  180. return WriteInt32Swap(f, (INT32)i);
  181. #else
  182. RETURN_IF_ERROR(WriteInt32Swap(f, (INT32)i));
  183. return WriteInt32Swap(f, (INT32)msb32);
  184. #endif
  185. }
  186. OP_STATUS BlockStorage::ReadOFL(OpLowLevelFile *f, OpFileLength *ofl)
  187. {
  188. RETURN_IF_ERROR(ReadInt64(f, ofl, NULL));
  189. return CheckFilePosition(*ofl);
  190. }
  191. OP_STATUS BlockStorage::WriteOFL(OpLowLevelFile *f, OpFileLength ofl)
  192. {
  193. RETURN_IF_ERROR(CheckFilePosition(ofl));
  194. return WriteInt64(f, ofl, 0);
  195. }
  196. OP_STATUS BlockStorage::ReadBlockHeader(OpLowLevelFile *f, OpFileLength *next_pos, BOOL *start_block)
  197. {
  198. UINT32 msb32;
  199. RETURN_IF_ERROR(ReadInt64(f, next_pos, &msb32));
  200. #ifdef ANY_INT64
  201. if (sizeof(OpFileLength) == 8)
  202. #ifdef OPERA_BIG_ENDIAN
  203. *((unsigned char *)next_pos) &= 0x7F;
  204. #else
  205. *(((unsigned char *)next_pos) + 7) &= 0x7F;
  206. #endif
  207. #else
  208. OP_ASSERT(sizeof(OpFileLength) == 4);
  209. #endif
  210. RETURN_IF_ERROR(CheckFilePosition(*next_pos));
  211. if (start_block != NULL)
  212. *start_block = (msb32 & (1u<<31)) == 0 && m_start_blocks_supported;
  213. return OpStatus::OK;
  214. }
  215. OP_STATUS BlockStorage::WriteBlockHeader(OpLowLevelFile *f, OpFileLength next_pos, BOOL start_block)
  216. {
  217. INT32 msb32 = !start_block && m_start_blocks_supported ? 1u << 31 : 0;
  218. RETURN_IF_ERROR(CheckFilePosition(next_pos));
  219. return WriteInt64(f, next_pos, msb32);
  220. }
  221. OP_STATUS BlockStorage::CheckFilePosition(OpFileLength pos)
  222. {
  223. #ifdef ANY_INT64
  224. if ((pos >> 31) >> 4 != 0 /* greater than 2^35 = 32GB, or negative */)
  225. {
  226. // Clearly something is amiss, ofl should not be this big
  227. // The search engine will be uselessly slow at this size anyway.
  228. OP_ASSERT(!"File position was incredibly large, probably a corrupt file. Contact search_engine module owner if reproducible");
  229. return OpStatus::ERR_OUT_OF_RANGE;
  230. }
  231. #endif
  232. if (!AT_BLOCK_BOUNDARY(pos))
  233. {
  234. OP_ASSERT(!"File position was not at a block boundary, probably a corrupt file. Contact search_engine module owner if reproducible");
  235. return OpStatus::ERR_OUT_OF_RANGE;
  236. }
  237. return OpStatus::OK;
  238. }
  239. BlockStorage::~BlockStorage(void)
  240. {
  241. UnGroup();
  242. if (m_file != NULL)
  243. Close();
  244. }
  245. static OP_STATUS OpenOpLowLevelFile(OpLowLevelFile **f, const uni_char* path, BlockStorage::OpenMode mode, OpFileFolder folder)
  246. {
  247. OpString full_path;
  248. OP_STATUS rv;
  249. int open_mode;
  250. BOOL e;
  251. if (*f != NULL)
  252. {
  253. OP_DELETE(*f);
  254. *f = NULL;
  255. }
  256. if (folder != OPFILE_ABSOLUTE_FOLDER && folder != OPFILE_SERIALIZED_FOLDER)
  257. {
  258. RETURN_IF_ERROR(g_folder_manager->GetFolderPath(folder, full_path));
  259. }
  260. RETURN_IF_ERROR(full_path.Append(path));
  261. RETURN_IF_ERROR(OpLowLevelFile::Create(f, full_path.CStr(), folder == OPFILE_SERIALIZED_FOLDER));
  262. if (OpStatus::IsError((*f)->Exists(&e)))
  263. e = TRUE;
  264. if (mode == BlockStorage::OpenRead)
  265. {
  266. if (e)
  267. open_mode = OPFILE_READ | OPFILE_SHAREDENYWRITE;
  268. else
  269. open_mode = OPFILE_READ | OPFILE_WRITE | OPFILE_SHAREDENYWRITE;
  270. }
  271. else {
  272. if (e)
  273. open_mode = OPFILE_UPDATE | OPFILE_SHAREDENYWRITE;
  274. else
  275. open_mode = OPFILE_READ | OPFILE_WRITE | OPFILE_SHAREDENYWRITE;
  276. }
  277. if (OpStatus::IsError(rv = (*f)->Open(open_mode)))
  278. {
  279. OP_DELETE(*f);
  280. *f = NULL;
  281. }
  282. return rv;
  283. }
  284. OP_STATUS BlockStorage::Open(const uni_char* path, OpenMode mode, int blocksize, int buffered_blocks, OpFileFolder folder)
  285. {
  286. m_blocksize = blocksize;
  287. m_buffered_blocks = buffered_blocks;
  288. OP_STATUS rv = OpStatus::OK;
  289. OP_BOOLEAN e;
  290. UINT32 header = BLOCK_FILE_HEADER;
  291. OpFileLength file_length;
  292. if (mode == OpenReadWrite && (blocksize < BLOCK_HDR_SIZE + 4 || blocksize < FILE_HDR_SIZE))
  293. return OpStatus::ERR_OUT_OF_RANGE;
  294. m_freeblock = (OpFileLength)(-1);
  295. do {
  296. RETURN_IF_ERROR(OpenOpLowLevelFile(&m_file, path, mode, folder));
  297. #ifndef DONT_BUFFER_BLOCK_STORAGE
  298. if (buffered_blocks > 0)
  299. {
  300. m_file = BufferedLowLevelFile::Create(m_file, rv, blocksize * buffered_blocks);
  301. RETURN_IF_ERROR_CLEANUP(rv);
  302. }
  303. #endif
  304. #ifdef SEARCH_ENGINE_EXPONENTIAL_GROWTH_FILE
  305. ExponentialGrowthFile* exp_growth_file = ExponentialGrowthFile::Create(m_file, rv);
  306. RETURN_IF_ERROR_CLEANUP(rv);
  307. m_file = exp_growth_file;
  308. #endif
  309. RETURN_IF_ERROR_CLEANUP(m_file->GetFileLength(&file_length));
  310. if (file_length < FILE_HDR_SIZE) // newly created or invalid file
  311. { // the file was rewritten
  312. ReadInt32 = ReadInt32Straight;
  313. WriteInt32 = WriteInt32Straight;
  314. ReadInt64 = ReadInt64Straight;
  315. WriteInt64 = WriteInt64Straight;
  316. m_start_blocks_supported = TRUE;
  317. // Since BlockStorage initialization is not protected by transactions, we must take
  318. // care to set the file-length of the initial block first, for this to work nicely
  319. // with ExponentialGrowthFile. (CORE-39213)
  320. RETURN_IF_ERROR_CLEANUP(m_file->SetFileLength(m_blocksize));
  321. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(0));
  322. RETURN_IF_ERROR_CLEANUP(WriteOFL(m_file, 0)); // free block
  323. header = BLOCK_FILE_HEADER;
  324. RETURN_IF_ERROR_CLEANUP(m_file->Write(&header, 4));
  325. RETURN_IF_ERROR_CLEANUP(WriteInt32(m_file, m_blocksize));
  326. if (m_blocksize > FILE_HDR_SIZE)
  327. {
  328. char zero = 0;
  329. for (file_length = FILE_HDR_SIZE; file_length < (unsigned int)m_blocksize; file_length++)
  330. RETURN_IF_ERROR_CLEANUP(m_file->Write(&zero, 1));
  331. }
  332. m_file->Flush();
  333. }
  334. else
  335. {
  336. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(BLOCK_HDR_SIZE));
  337. RETURN_IF_ERROR_CLEANUP(ReadFully(m_file, &header, 4));
  338. switch (header) {
  339. case OLD_JOURNAL_FILE_HEADER_I:
  340. ReadInt32 = ReadInt32Swap;
  341. WriteInt32 = WriteInt32Swap;
  342. ReadInt64 = ReadInt64Swap;
  343. WriteInt64 = WriteInt64Swap;
  344. m_start_blocks_supported = FALSE;
  345. // no break
  346. case OLD_JOURNAL_FILE_HEADER:
  347. RETURN_IF_ERROR_CLEANUP(e = DeleteAssociatedFile(INVALID_JOURNAL_SUFFIX));
  348. if (e == OpBoolean::IS_TRUE)
  349. {
  350. RETURN_IF_ERROR_CLEANUP(DeleteAssociatedFile(TRANSACTION_NAME_SUFFIX));
  351. }
  352. else {
  353. RETURN_IF_ERROR_CLEANUP(e = DeleteAssociatedFile(TRANSACTION_NAME_SUFFIX));
  354. if (e == OpBoolean::IS_TRUE)
  355. {
  356. m_file->Close();
  357. m_file->Delete();
  358. OP_DELETE(m_file);
  359. m_file = NULL;
  360. continue;
  361. }
  362. }
  363. header = ((header == OLD_JOURNAL_FILE_HEADER) ? BLOCK_FILE_HEADER_0201 : BLOCK_FILE_HEADER_0201_I);
  364. if (mode != OpenRead)
  365. {
  366. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(BLOCK_HDR_SIZE));
  367. RETURN_IF_ERROR_CLEANUP(m_file->Write(&header, 4));
  368. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(BLOCK_HDR_SIZE + 4));
  369. }
  370. if (header == BLOCK_FILE_HEADER_0201_I)
  371. break;
  372. // no break
  373. case BLOCK_FILE_HEADER:
  374. case BLOCK_FILE_HEADER_0201:
  375. case BLOCK_FILE_HEADER_0202:
  376. ReadInt32 = ReadInt32Straight;
  377. WriteInt32 = WriteInt32Straight;
  378. ReadInt64 = ReadInt64Straight;
  379. WriteInt64 = WriteInt64Straight;
  380. m_start_blocks_supported = header == BLOCK_FILE_HEADER || header == BLOCK_FILE_HEADER_0202;
  381. break;
  382. case BLOCK_FILE_HEADER_I:
  383. case BLOCK_FILE_HEADER_0201_I:
  384. case BLOCK_FILE_HEADER_0202_I:
  385. ReadInt32 = ReadInt32Swap;
  386. WriteInt32 = WriteInt32Swap;
  387. ReadInt64 = ReadInt64Swap;
  388. WriteInt64 = WriteInt64Swap;
  389. m_start_blocks_supported = header == BLOCK_FILE_HEADER_I || header == BLOCK_FILE_HEADER_0202;
  390. break;
  391. default:
  392. RETURN_IF_ERROR_CLEANUP(DeleteAssociatedFile(TRANSACTION_NAME_SUFFIX));
  393. RETURN_IF_ERROR_CLEANUP(DeleteAssociatedFile(INVALID_JOURNAL_SUFFIX));
  394. RETURN_IF_ERROR_CLEANUP(DeleteAssociatedFile(ATOMIC_COMMIT_IN_PROGRESS_SUFFIX));
  395. m_file->Close();
  396. m_file->Delete();
  397. OP_DELETE(m_file);
  398. m_file = NULL;
  399. continue;
  400. }
  401. INT32 bs;
  402. if (OpStatus::IsError(ReadInt32(m_file, &bs)))
  403. {
  404. m_file->Close();
  405. OP_DELETE(m_file);
  406. m_file = NULL;
  407. return OpStatus::ERR_PARSING_FAILED;
  408. }
  409. m_blocksize = bs;
  410. }
  411. #ifdef SEARCH_ENGINE_EXPONENTIAL_GROWTH_FILE
  412. if (header == BLOCK_FILE_HEADER_0202 || header == BLOCK_FILE_HEADER_0202_I)
  413. {
  414. if (mode == OpenReadWrite)
  415. {
  416. // Upgrade to new file format version
  417. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(BLOCK_HDR_SIZE));
  418. RETURN_IF_ERROR_CLEANUP(WriteInt32(m_file, BLOCK_FILE_HEADER)); // Becomes correct according to endianness
  419. }
  420. }
  421. else if (header != BLOCK_FILE_HEADER && header != BLOCK_FILE_HEADER_I && exp_growth_file)
  422. {
  423. // If an old format is still around, it cannot be upgraded to use exponential growth
  424. m_file = ExponentialGrowthFile::MakeNormalFile(exp_growth_file);
  425. }
  426. #endif
  427. // Enforce atomic group commit
  428. if (this == GetFirstInGroup())
  429. {
  430. // Check the atomic group commit in progress marker
  431. if (AssociatedFileExists(ATOMIC_COMMIT_IN_PROGRESS_SUFFIX) == OpBoolean::IS_TRUE)
  432. m_group_commit_incomplete = TRUE;
  433. }
  434. // If we didn't manage to complete last commit atomically, assume committed
  435. // anyway, so none in the group should roll back
  436. if (GetFirstInGroup()->m_group_commit_incomplete)
  437. RETURN_IF_ERROR_CLEANUP(DeleteAssociatedFile(TRANSACTION_NAME_SUFFIX));
  438. // Last in group deletes the atomic commit marker (for all)
  439. BOOL last_in_group = TRUE;
  440. BlockStorage *member;
  441. for (member = m_next_in_group; member != this; member = member->m_next_in_group)
  442. if (!member->m_file)
  443. last_in_group = FALSE; // If another member is not opened, this is not the last
  444. if (last_in_group)
  445. {
  446. OpStatus::Ignore(DeleteAssociatedFile(ATOMIC_COMMIT_IN_PROGRESS_SUFFIX));
  447. for (member = m_next_in_group; member != this; member = member->m_next_in_group)
  448. OpStatus::Ignore(member->DeleteAssociatedFile(ATOMIC_COMMIT_IN_PROGRESS_SUFFIX));
  449. }
  450. RETURN_IF_ERROR_CLEANUP(e = AssociatedFileExists(TRANSACTION_NAME_SUFFIX));
  451. if (e == OpBoolean::IS_TRUE)
  452. {
  453. if (mode == OpenRead)
  454. {
  455. m_file->Close();
  456. if (OpStatus::IsError(rv = m_file->Open(OPFILE_UPDATE | OPFILE_SHAREDENYWRITE)))
  457. {
  458. OP_DELETE(m_file);
  459. m_file = NULL;
  460. return rv;
  461. }
  462. }
  463. if (OpStatus::IsError(rv = Rollback()))
  464. {
  465. OpStatus::Ignore(DeleteAssociatedFile(TRANSACTION_NAME_SUFFIX));
  466. m_file->Close();
  467. m_file->Delete();
  468. OP_DELETE(m_file);
  469. m_file = NULL;
  470. return rv;
  471. }
  472. if (mode == OpenRead)
  473. {
  474. m_file->Close();
  475. if (OpStatus::IsError(rv = m_file->Open(OPFILE_READ | OPFILE_SHAREDENYWRITE)))
  476. {
  477. OP_DELETE(m_file);
  478. m_file = NULL;
  479. return rv;
  480. }
  481. }
  482. }
  483. break;
  484. } while (1);
  485. return OpStatus::OK;
  486. cleanup:
  487. m_file->Close();
  488. OP_DELETE(m_file);
  489. m_file = NULL;
  490. return rv;
  491. }
  492. void BlockStorage::Close(void)
  493. {
  494. if (InTransaction())
  495. OpStatus::Ignore(Commit());
  496. if (WaitingForGroupCommit()) // Not all in the group were committed. (Disk full or something)
  497. OpStatus::Ignore(Rollback());
  498. if (m_file != NULL) {
  499. m_file->Close();
  500. OP_DELETE(m_file);
  501. m_file = NULL;
  502. }
  503. }
  504. #ifdef SELFTEST
  505. void BlockStorage::Crash(void)
  506. {
  507. if (m_transaction != NULL)
  508. {
  509. m_transaction->Close();
  510. OP_DELETE(m_transaction);
  511. m_transaction = NULL;
  512. }
  513. if (m_file != NULL) {
  514. m_file->Close();
  515. OP_DELETE(m_file);
  516. m_file = NULL;
  517. }
  518. }
  519. #endif
  520. OP_STATUS BlockStorage::Clear(int blocksize)
  521. {
  522. uni_char *fname;
  523. OP_STATUS rv;
  524. if (m_file == NULL)
  525. return OpStatus::ERR;
  526. if (m_transaction != NULL)
  527. {
  528. m_transaction->Close();
  529. m_transaction->Delete();
  530. OP_DELETE(m_transaction);
  531. m_transaction = NULL;
  532. }
  533. RETURN_OOM_IF_NULL(fname = uni_strdup(m_file->GetFullPath()));
  534. Close();
  535. RETURN_IF_ERROR(DeleteFile(fname));
  536. if (blocksize <= 0)
  537. blocksize = m_blocksize;
  538. rv = Open(fname, OpenReadWrite, blocksize, m_buffered_blocks);
  539. op_free(fname);
  540. return rv;
  541. }
  542. BOOL BlockStorage::IsNativeEndian(void) const
  543. {
  544. return ReadInt32 != ReadInt32Swap;
  545. }
  546. void BlockStorage::SetOnTheFlyCnvFunc(SwitchEndianCallback cb, void *user_arg)
  547. {
  548. m_EndianCallback = cb;
  549. m_callback_arg = user_arg;
  550. }
  551. void BlockStorage::SwitchEndian(void *buf, int size)
  552. {
  553. register unsigned char tmp;
  554. register int pos;
  555. --size;
  556. for (pos = (size - 1) / 2; pos >= 0; --pos)
  557. {
  558. tmp = ((unsigned char *)buf)[pos];
  559. ((unsigned char *)buf)[pos] = ((unsigned char *)buf)[size - pos];
  560. ((unsigned char *)buf)[size - pos] = tmp;
  561. }
  562. }
  563. OP_STATUS BlockStorage::BeginTransaction(BOOL invalidate_journal)
  564. {
  565. char *bitmap;
  566. unsigned int i;
  567. OP_STATUS rv = OpStatus::OK;
  568. OpFileLength file_length;
  569. if (m_file == NULL || m_transaction != NULL)
  570. return OpStatus::ERR;
  571. #ifdef _DEBUG
  572. m_journal_invalid = invalidate_journal;
  573. #endif
  574. OP_ASSERT(m_reserved_area == 0 && m_reserved_size == 0 && m_reserved_deleted == INVALID_FILE_LENGTH);
  575. m_file->Flush();
  576. RETURN_IF_ERROR(m_journal_compressor.InitCompDict());
  577. RETURN_IF_ERROR(m_file->GetFileLength(&file_length));
  578. RETURN_IF_ERROR(OpenAssociatedFile(&m_transaction, OpenReadWrite, TRANSACTION_NAME_SUFFIX));
  579. // prepare a bit map for saved pages
  580. RETURN_IF_ERROR_CLEANUP(WriteOFL(m_transaction, file_length));
  581. if ((bitmap = OP_NEWA(char, (unsigned int)((file_length / m_blocksize + 7) >> 3))) == NULL)
  582. {
  583. char zero = 0;
  584. for (i = (unsigned int)((file_length / m_blocksize + 7) >> 3); i > 0; --i)
  585. RETURN_IF_ERROR_CLEANUP(m_transaction->Write(&zero, 1));
  586. }
  587. else {
  588. op_memset(bitmap, 0, (unsigned int)((file_length / m_blocksize + 7) >> 3));
  589. rv = m_transaction->Write(bitmap, (unsigned int)((file_length / m_blocksize + 7) >> 3));
  590. OP_DELETEA(bitmap);
  591. if (OpStatus::IsError(rv))
  592. goto cleanup;
  593. }
  594. m_transaction_blocks = (unsigned int)(file_length / m_blocksize);
  595. m_transaction->Flush();
  596. RETURN_IF_ERROR_CLEANUP(JournalBlock(0));
  597. if (invalidate_journal)
  598. {
  599. OpLowLevelFile *f = NULL;
  600. RETURN_IF_ERROR_CLEANUP(OpenAssociatedFile(&f, OpenReadWrite, INVALID_JOURNAL_SUFFIX));
  601. if (OpStatus::IsError(rv = WriteOFL(f, file_length)))
  602. {
  603. f->Close();
  604. f->Delete();
  605. OP_DELETE(f);
  606. goto cleanup;
  607. }
  608. f->SafeClose();
  609. OP_DELETE(f);
  610. }
  611. else
  612. RETURN_IF_ERROR_CLEANUP(DeleteAssociatedFile(INVALID_JOURNAL_SUFFIX)); // delete the file if it exists
  613. return OpStatus::OK;
  614. cleanup:
  615. m_transaction->Close();
  616. m_transaction->Delete();
  617. OP_DELETE(m_transaction);
  618. m_transaction = NULL;
  619. return rv;
  620. }
  621. OP_STATUS BlockStorage::Commit(void)
  622. {
  623. OP_BOOLEAN rv;
  624. if (m_transaction == NULL)
  625. return OpStatus::ERR;
  626. if (WaitingForGroupCommit())
  627. return OpStatus::OK; // And we're still WaitingForGroupCommit()...
  628. RETURN_IF_ERROR(rv = AssociatedFileExists(INVALID_JOURNAL_SUFFIX));
  629. if (rv == OpBoolean::IS_TRUE)
  630. {
  631. OP_ASSERT(0); // you have probably called BeginTransaction(TRUE), but haven't called FlushJournal()
  632. RETURN_IF_ERROR(FlushJournal());
  633. }
  634. OP_ASSERT(m_reserved_area == 0 && m_reserved_size == 0 && m_reserved_deleted == INVALID_FILE_LENGTH);
  635. m_journal_compressor.FreeCompDict();
  636. if ((OpStatus::IsError(rv = m_file->SafeClose())))
  637. {
  638. if (m_file->IsOpen())
  639. return rv;
  640. }
  641. else
  642. rv = m_file->Open(OPFILE_UPDATE | OPFILE_SHAREDENYWRITE);
  643. m_transaction->Close(); // From this point, WaitingForGroupCommit() will return TRUE
  644. if (m_transaction->IsOpen())
  645. rv = OpStatus::ERR;
  646. if (OpStatus::IsError(rv))
  647. {
  648. OP_DELETE(m_file);
  649. m_file = NULL;
  650. OP_DELETE(m_transaction);
  651. m_transaction = NULL;
  652. return rv;
  653. }
  654. BlockStorage *group_member;
  655. BOOL ready = TRUE;
  656. for (group_member = m_next_in_group; group_member != this; group_member = group_member->m_next_in_group)
  657. if (group_member->InTransaction() && !group_member->WaitingForGroupCommit())
  658. ready = FALSE;
  659. if (ready)
  660. {
  661. // Create "atomic group commit in progress" marker
  662. rv = GetFirstInGroup()->CreateAssociatedFile(ATOMIC_COMMIT_IN_PROGRESS_SUFFIX);
  663. // From this point, the commit should take effect even if we crash
  664. // Finish commit for all in group
  665. group_member = this;
  666. do
  667. {
  668. if (group_member->WaitingForGroupCommit())
  669. {
  670. OP_STATUS status = group_member->m_transaction->Delete();
  671. OP_DELETE(group_member->m_transaction);
  672. group_member->m_transaction = NULL;
  673. rv = OpStatus::IsError(rv) ? rv : status;
  674. }
  675. group_member = group_member->m_next_in_group;
  676. }
  677. while (group_member != this);
  678. // Remove "atomic group commit in progress" marker
  679. if (OpStatus::IsSuccess(rv))
  680. rv = GetFirstInGroup()->DeleteAssociatedFile(ATOMIC_COMMIT_IN_PROGRESS_SUFFIX);
  681. }
  682. return rv;
  683. }
  684. OP_STATUS BlockStorage::Rollback(void)
  685. {
  686. unsigned char in_journal;
  687. OpFileLength pos, origin=0, original_length=0, file_length, current_file_length;
  688. OP_BOOLEAN e;
  689. OP_STATUS rv = OpStatus::OK;
  690. char *blockbuf = NULL;
  691. unsigned char *compressed_buf = NULL;
  692. INT32 c_size;
  693. unsigned chk_size;
  694. if (m_file == NULL)
  695. return OpStatus::ERR;
  696. if (WaitingForGroupCommit()) // Not all in the group were committed. (Disk full or something)
  697. {
  698. // m_transaction is closed, make sure it is reopened
  699. OP_DELETE(m_transaction);
  700. m_transaction = NULL;
  701. }
  702. RETURN_IF_ERROR(e = AssociatedFileExists(INVALID_JOURNAL_SUFFIX));
  703. if (e == OpBoolean::IS_TRUE)
  704. {
  705. OpLowLevelFile *f = NULL;
  706. RETURN_IF_ERROR(m_file->GetFileLength(&file_length));
  707. RETURN_IF_ERROR(OpenAssociatedFile(&f, OpenReadWrite, INVALID_JOURNAL_SUFFIX));
  708. e = ReadOFL(f, &original_length);
  709. f->Close();
  710. OP_DELETE(f);
  711. RETURN_IF_ERROR(e);
  712. if (file_length > original_length)
  713. {
  714. RETURN_IF_ERROR(m_file->SetFileLength(original_length));
  715. }
  716. if (m_transaction == NULL)
  717. {
  718. RETURN_IF_ERROR(DeleteAssociatedFile(TRANSACTION_NAME_SUFFIX));
  719. }
  720. else {
  721. m_transaction->Close();
  722. e = m_transaction->Delete();
  723. OP_DELETE(m_transaction);
  724. m_transaction = NULL;
  725. RETURN_IF_ERROR(e);
  726. }
  727. OpStatus::Ignore(DeleteAssociatedFile(INVALID_JOURNAL_SUFFIX)); // no error check
  728. m_freeblock = INVALID_FILE_LENGTH;
  729. m_reserved_area = 0;
  730. m_reserved_size = 0;
  731. m_reserved_deleted = INVALID_FILE_LENGTH;
  732. m_journal_compressor.FreeCompDict();
  733. return OpStatus::OK;
  734. }
  735. if (m_transaction == NULL)
  736. {
  737. RETURN_IF_ERROR(e = AssociatedFileExists(TRANSACTION_NAME_SUFFIX));
  738. if (e != OpBoolean::IS_TRUE)
  739. return e == OpBoolean::IS_FALSE ? OpStatus::ERR : e;
  740. RETURN_IF_ERROR(OpenAssociatedFile(&m_transaction, OpenRead, TRANSACTION_NAME_SUFFIX));
  741. }
  742. else
  743. m_transaction->Flush();
  744. RETURN_IF_ERROR_CLEANUP(m_transaction->GetFileLength(&file_length));
  745. if (file_length == 0)
  746. {
  747. // It is an invalid/empty journal, so nothing to roll back. Just hope everything is OK (bug DSK-238400)
  748. goto rollback_ok;
  749. }
  750. RETURN_IF_ERROR_CLEANUP(m_transaction->SetFilePos(0));
  751. RETURN_IF_ERROR_CLEANUP(ReadOFL(m_transaction, &original_length));
  752. pos = JOURNAL_HDR_SIZE + ((original_length / m_blocksize + 7) >> 3);
  753. RETURN_IF_ERROR_CLEANUP(m_transaction->SetFilePos(pos));
  754. RETURN_OOM_IF_NULL(compressed_buf = OP_NEWA(unsigned char, ((3 * m_blocksize) >> 1) + 8));
  755. if ((blockbuf = OP_NEWA(char, m_blocksize)) == NULL)
  756. {
  757. OP_DELETEA(compressed_buf);
  758. return OpStatus::ERR_NO_MEMORY;
  759. }
  760. while (file_length > pos)
  761. {
  762. RETURN_IF_ERROR_CLEANUP(ReadOFL(m_transaction, &origin));
  763. // check if this page had been successfully journalled
  764. RETURN_IF_ERROR_CLEANUP(m_transaction->SetFilePos(JOURNAL_HDR_SIZE + ((origin / m_blocksize) >> 3)));
  765. RETURN_IF_ERROR_CLEANUP(ReadFully(m_transaction, &in_journal, 1));
  766. if ((in_journal & (1 << ((origin / m_blocksize) & 7))) == 0)
  767. break;
  768. RETURN_IF_ERROR_CLEANUP(m_transaction->SetFilePos(pos + 8));
  769. RETURN_IF_ERROR_CLEANUP(ReadInt32(m_transaction, &c_size));
  770. OP_ASSERT(c_size <= ((3 * m_blocksize) >> 1) + 8);
  771. RETURN_IF_ERROR_CLEANUP(ReadFully(m_transaction, compressed_buf, c_size));
  772. chk_size = m_journal_compressor.Decompress(blockbuf, compressed_buf, c_size);
  773. OP_ASSERT(chk_size == (unsigned)m_blocksize);
  774. if (chk_size != (unsigned)m_blocksize) RETURN_IF_ERROR_CLEANUP(OpStatus::ERR);
  775. RETURN_IF_ERROR_CLEANUP(m_file->GetFileLength(&current_file_length));
  776. if (current_file_length < origin)
  777. RETURN_IF_ERROR_CLEANUP(m_file->SetFileLength(origin));
  778. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(origin));
  779. RETURN_IF_ERROR_CLEANUP(m_file->Write(blockbuf, m_blocksize));
  780. pos += 12 + c_size;
  781. }
  782. OP_DELETEA(compressed_buf);
  783. compressed_buf = NULL;
  784. OP_DELETEA(blockbuf);
  785. blockbuf = NULL;
  786. m_file->Flush();
  787. m_freeblock = INVALID_FILE_LENGTH;
  788. RETURN_IF_ERROR_CLEANUP(m_file->GetFileLength(&file_length));
  789. if (file_length != original_length)
  790. RETURN_IF_ERROR_CLEANUP(m_file->SetFileLength(original_length));
  791. rollback_ok:
  792. m_reserved_area = 0;
  793. m_reserved_size = 0;
  794. m_reserved_deleted = INVALID_FILE_LENGTH;
  795. m_transaction->Close();
  796. m_transaction->Delete();
  797. OP_DELETE(m_transaction);
  798. m_transaction = NULL;
  799. m_journal_compressor.FreeCompDict();
  800. return OpStatus::OK;
  801. cleanup:
  802. m_transaction->Close();
  803. OP_DELETE(m_transaction);
  804. m_transaction = NULL;
  805. if (blockbuf != NULL)
  806. OP_DELETEA(blockbuf);
  807. if (compressed_buf != NULL)
  808. OP_DELETEA(compressed_buf);
  809. return rv;
  810. }
  811. OP_STATUS BlockStorage::PreJournal(OpFileLength pos)
  812. {
  813. OpFileLength bitfield_pos;
  814. if (!InTransaction())
  815. return OpStatus::ERR;
  816. OP_ASSERT(IS_START_BLOCK(pos));
  817. if (pos / m_blocksize >= (OpFileLength)m_transaction_blocks)
  818. return OpStatus::OK;
  819. while (pos != 0)
  820. {
  821. RETURN_IF_ERROR(JournalBlock(pos));
  822. bitfield_pos = BITFIELD_POS(pos);
  823. RETURN_IF_ERROR(JournalBlock(bitfield_pos));
  824. OP_ASSERT(IS_NORMAL_BLOCK(pos));
  825. RETURN_IF_ERROR(m_file->SetFilePos(pos));
  826. RETURN_IF_ERROR(ReadBlockHeader(m_file, &pos));
  827. }
  828. return OpStatus::OK;
  829. }
  830. OP_STATUS BlockStorage::FlushJournal(void)
  831. {
  832. OP_STATUS rv = OpStatus::OK;
  833. OpFileLength bitfield_pos, fsize;
  834. if (!InTransaction())
  835. return OpStatus::ERR;
  836. if (m_reserved_area != 0)
  837. {
  838. fsize = m_reserved_area;
  839. // strip the exceeding piece of file
  840. if (m_reserved_size != 0)
  841. RETURN_IF_ERROR(m_file->SetFileLength(fsize));
  842. }
  843. else {
  844. RETURN_IF_ERROR(m_file->Flush());
  845. RETURN_IF_ERROR(m_file->GetFileLength(&fsize));
  846. }
  847. RETURN_IF_ERROR_CLEANUP(m_transaction->SafeClose());
  848. rv = DeleteAssociatedFile(INVALID_JOURNAL_SUFFIX);
  849. if (OpStatus::IsError(rv))
  850. {
  851. RETURN_IF_ERROR_CLEANUP(m_transaction->Open(OPFILE_UPDATE | OPFILE_SHAREDENYWRITE));
  852. return rv;
  853. }
  854. if (m_freeblock != INVALID_FILE_LENGTH)
  855. {
  856. int fi;
  857. OpFileLength fill = 0;
  858. unsigned char c;
  859. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(0));
  860. RETURN_IF_ERROR_CLEANUP(ReadOFL(m_file, &bitfield_pos));
  861. while (bitfield_pos < m_freeblock || (m_freeblock == 0 && bitfield_pos < fsize && bitfield_pos > 0))
  862. {
  863. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(bitfield_pos));
  864. for (fi = m_blocksize / sizeof(fill); fi > 0; --fi)
  865. RETURN_IF_ERROR_CLEANUP(m_file->Write(&fill, sizeof(fill)));
  866. if (m_blocksize % sizeof(fill) != 0)
  867. RETURN_IF_ERROR_CLEANUP(m_file->Write(&fill, m_blocksize % sizeof(fill)));
  868. bitfield_pos += DISTANCE_BETWEEN_BITFIELDS;
  869. }
  870. // if m_freeblock == 0, it was already cleared
  871. if (m_freeblock != 0 && m_reserved_deleted != INVALID_FILE_LENGTH && m_reserved_deleted > (OpFileLength)m_blocksize && m_reserved_deleted - m_blocksize > m_freeblock)
  872. {
  873. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(bitfield_pos));
  874. if (((int)((m_reserved_deleted - bitfield_pos) / m_blocksize) - 1) > 0)
  875. {
  876. for (fi = 0; fi < ((int)((m_reserved_deleted - bitfield_pos) / m_blocksize) - 1) / 8; ++fi)
  877. RETURN_IF_ERROR_CLEANUP(m_file->Write(&fill, 1));
  878. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(bitfield_pos + fi));
  879. }
  880. RETURN_IF_ERROR_CLEANUP(ReadFully(m_file, &c, 1));
  881. c &= ((unsigned char)0xFF) << ((int)((m_reserved_deleted - bitfield_pos) / m_blocksize - 1) & 7);
  882. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos((OpFileLength)-1, SEEK_FROM_CURRENT));
  883. RETURN_IF_ERROR_CLEANUP(m_file->Write(&c, 1));
  884. }
  885. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(0));
  886. RETURN_IF_ERROR_CLEANUP(WriteOFL(m_file, m_freeblock));
  887. }
  888. m_reserved_area = 0;
  889. m_reserved_size = 0;
  890. m_reserved_deleted = INVALID_FILE_LENGTH;
  891. #ifdef _DEBUG
  892. m_journal_invalid = FALSE;
  893. #endif
  894. RETURN_IF_ERROR_CLEANUP(m_transaction->Open(OPFILE_UPDATE | OPFILE_SHAREDENYWRITE));
  895. return OpStatus::OK;
  896. cleanup:
  897. m_file->Close();
  898. OP_DELETE(m_file);
  899. m_file = NULL;
  900. m_transaction->Close();
  901. OP_DELETE(m_transaction);
  902. m_transaction = NULL;
  903. return rv;
  904. }
  905. // must be bigger than 1
  906. #define BS_RESERVE_BLOCKS 16
  907. OpFileLength BlockStorage::Reserve()
  908. {
  909. OpFileLength pos, bitfield_pos;
  910. OP_ASSERT(!WaitingForGroupCommit());
  911. if (m_freeblock == INVALID_FILE_LENGTH)
  912. {
  913. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(0), 0);
  914. RETURN_VALUE_IF_ERROR(ReadOFL(m_file, &m_freeblock), 0);
  915. }
  916. if (m_freeblock != 0)
  917. {
  918. if ((pos = GetFreeBlock(FALSE)) == 0)
  919. return 0;
  920. }
  921. else {
  922. while (m_reserved_size > 0)
  923. {
  924. pos = m_reserved_area;
  925. m_reserved_area += m_blocksize;
  926. m_reserved_size -= m_blocksize;
  927. if (IS_BITFIELD_BLOCK(pos))
  928. continue;
  929. return pos;
  930. }
  931. m_file->Flush();
  932. RETURN_VALUE_IF_ERROR(m_file->GetFileLength(&pos), 0);
  933. RETURN_VALUE_IF_ERROR(m_file->SetFileLength(pos + m_blocksize * BS_RESERVE_BLOCKS), 0);
  934. m_reserved_area = pos + m_blocksize; // because pos is already taken as reserved
  935. m_reserved_size = m_blocksize * (BS_RESERVE_BLOCKS - 1);
  936. for (bitfield_pos = m_reserved_area - m_blocksize; bitfield_pos < m_reserved_area + m_reserved_size; bitfield_pos += m_blocksize)
  937. {
  938. if (IS_BITFIELD_BLOCK(bitfield_pos))
  939. {
  940. int fi;
  941. OpFileLength fill = 0;
  942. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(bitfield_pos), 0);
  943. for (fi = m_blocksize / sizeof(fill); fi > 0; --fi)
  944. RETURN_VALUE_IF_ERROR(m_file->Write(&fill, sizeof(fill)), 0);
  945. if (m_blocksize % sizeof(fill) != 0)
  946. RETURN_VALUE_IF_ERROR(m_file->Write(&fill, m_blocksize % sizeof(fill)), 0);
  947. }
  948. }
  949. if (IS_BITFIELD_BLOCK(pos))
  950. {
  951. pos += m_blocksize;
  952. m_reserved_area += m_blocksize;
  953. m_reserved_size -= m_blocksize;
  954. }
  955. }
  956. return pos;
  957. }
  958. OpFileLength BlockStorage::Write(const void *data, int len, OpFileLength reserved_pos)
  959. {
  960. void *orig_data;
  961. int size, orig_len;
  962. OpFileLength pos = 0;
  963. OpFileLength head = 0;
  964. OP_STATUS rv = OpStatus::OK;
  965. if (m_file == NULL)
  966. return 0;
  967. #ifdef _DEBUG
  968. OP_ASSERT(!InTransaction() || !m_journal_invalid);
  969. #endif
  970. OP_ASSERT(!WaitingForGroupCommit());
  971. if (reserved_pos == 0)
  972. {
  973. if ((head = CreateBlock(0, FALSE)) == 0)
  974. return 0;
  975. }
  976. else {
  977. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(reserved_pos), 0);
  978. RETURN_VALUE_IF_ERROR(WriteBlockHeader(m_file, 0, TRUE), 0);
  979. head = reserved_pos;
  980. }
  981. orig_data = (void *)data;
  982. orig_len = len;
  983. if (m_EndianCallback != NULL)
  984. SwitchEndianInData(orig_data, len);
  985. OP_ASSERT(IS_NORMAL_BLOCK(head));
  986. size = len > m_blocksize - BLOCK_HDR_SIZE - 4 ? m_blocksize - BLOCK_HDR_SIZE - 4 : len;
  987. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(head + BLOCK_HDR_SIZE));
  988. RETURN_IF_ERROR_CLEANUP(WriteInt32(m_file, len));
  989. if (size > 0) {
  990. RETURN_IF_ERROR_CLEANUP(m_file->Write(data, size));
  991. data = (const char *)data + size;
  992. len -= size;
  993. }
  994. pos = head;
  995. while (len > 0)
  996. {
  997. if ((pos = CreateBlock(pos, pos == head)) == 0) {
  998. if (!Delete(head))
  999. goto cleanup; // Avoid warning
  1000. goto cleanup;
  1001. }
  1002. OP_ASSERT(IS_NORMAL_BLOCK(pos));
  1003. size = len > m_blocksize - BLOCK_HDR_SIZE ? m_blocksize - BLOCK_HDR_SIZE : len;
  1004. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos + BLOCK_HDR_SIZE));
  1005. RETURN_IF_ERROR_CLEANUP(m_file->Write(data, size));
  1006. data = (const char *)data + size;
  1007. len -= size;
  1008. }
  1009. m_file->Flush();
  1010. if (m_EndianCallback != NULL)
  1011. SwitchEndianInData(orig_data, orig_len);
  1012. return head;
  1013. cleanup:
  1014. if (m_EndianCallback != NULL)
  1015. SwitchEndianInData(orig_data, orig_len);
  1016. return 0;
  1017. }
  1018. OpFileLength BlockStorage::Write(const void *data, int len)
  1019. {
  1020. return Write(data, len, 0);
  1021. }
  1022. int BlockStorage::DataLength(OpFileLength pos)
  1023. {
  1024. INT32 data_length;
  1025. if (m_file == NULL)
  1026. return 0;
  1027. if (!IS_START_BLOCK(pos))
  1028. {
  1029. OP_ASSERT(0);
  1030. return 0;
  1031. }
  1032. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos + 8), 0);
  1033. RETURN_VALUE_IF_ERROR(ReadInt32(m_file, &data_length), 0);
  1034. if (data_length < 0 || data_length > 16777216)
  1035. {
  1036. OP_ASSERT(0); // if you really want to read 16MB of memory, this assert is incorrect
  1037. // proper, but slower check would be m_last_block_header.data_length < GetFileSize()
  1038. return 0;
  1039. }
  1040. return data_length;
  1041. }
  1042. BOOL BlockStorage::Read(void *data, int len, OpFileLength pos)
  1043. {
  1044. void *orig_data;
  1045. int size, orig_len;
  1046. OpFileLength next;
  1047. INT32 maxlen;
  1048. if (m_file == NULL || len <= 0)
  1049. return FALSE;
  1050. orig_data = data;
  1051. orig_len = len;
  1052. OP_ASSERT(IS_START_BLOCK(pos));
  1053. m_file->Flush();
  1054. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos), FALSE);
  1055. RETURN_VALUE_IF_ERROR(ReadBlockHeader(m_file, &next), FALSE);
  1056. RETURN_VALUE_IF_ERROR(ReadInt32(m_file, &maxlen), FALSE);
  1057. if (len > maxlen)
  1058. {
  1059. OP_ASSERT(0);
  1060. return FALSE;
  1061. }
  1062. size = len > m_blocksize - BLOCK_HDR_SIZE - 4 ? m_blocksize - BLOCK_HDR_SIZE - 4 : len;
  1063. if (size > 0)
  1064. RETURN_VALUE_IF_ERROR(ReadFully(m_file, data, size), FALSE);
  1065. len -= size;
  1066. while (len > 0)
  1067. {
  1068. if (next == 0) // not enough data in the file
  1069. return FALSE;
  1070. data = (char *)data + size;
  1071. OP_ASSERT(IS_NOT_START_BLOCK(next));
  1072. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(next), FALSE);
  1073. RETURN_VALUE_IF_ERROR(ReadBlockHeader(m_file, &next), FALSE);
  1074. size = len > m_blocksize - BLOCK_HDR_SIZE ? m_blocksize - BLOCK_HDR_SIZE : len;
  1075. RETURN_VALUE_IF_ERROR(ReadFully(m_file, data, size), FALSE);
  1076. len -= size;
  1077. }
  1078. if (m_EndianCallback != NULL)
  1079. SwitchEndianInData(orig_data, orig_len);
  1080. return TRUE;
  1081. }
  1082. BOOL BlockStorage::Update(const void *data, int len, OpFileLength pos)
  1083. {
  1084. void *orig_data;
  1085. int size, orig_len;
  1086. OpFileLength orig_pos, next;
  1087. OP_STATUS rv = OpStatus::OK;
  1088. if (m_file == NULL)
  1089. return FALSE;
  1090. #ifdef _DEBUG
  1091. OP_ASSERT(!InTransaction() || !m_journal_invalid);
  1092. #endif
  1093. OP_ASSERT(IS_START_BLOCK(pos));
  1094. OP_ASSERT(!WaitingForGroupCommit());
  1095. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos), FALSE);
  1096. RETURN_VALUE_IF_ERROR(ReadBlockHeader(m_file, &next), FALSE);
  1097. if (InTransaction())
  1098. RETURN_VALUE_IF_ERROR(JournalBlock(pos), FALSE);
  1099. orig_data = (void *)data;
  1100. orig_len = len;
  1101. orig_pos = pos;
  1102. if (m_EndianCallback != NULL)
  1103. SwitchEndianInData(orig_data, len);
  1104. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos + BLOCK_HDR_SIZE));
  1105. size = len > m_blocksize - BLOCK_HDR_SIZE - 4 ? m_blocksize - BLOCK_HDR_SIZE - 4 : len;
  1106. RETURN_IF_ERROR_CLEANUP(WriteInt32(m_file, len));
  1107. if (size > 0) {
  1108. RETURN_IF_ERROR_CLEANUP(m_file->Write(data, size));
  1109. data = (const char *)data + size;
  1110. len -= size;
  1111. }
  1112. while (len > 0)
  1113. {
  1114. if (next != 0)
  1115. {
  1116. pos = next;
  1117. if (InTransaction())
  1118. RETURN_IF_ERROR_CLEANUP(JournalBlock(pos));
  1119. }
  1120. else {
  1121. if ((pos = CreateBlock(pos, pos == orig_pos)) == 0)
  1122. goto cleanup;
  1123. }
  1124. OP_ASSERT(IS_NOT_START_BLOCK(pos));
  1125. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos));
  1126. RETURN_IF_ERROR_CLEANUP(ReadBlockHeader(m_file, &next));
  1127. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos + BLOCK_HDR_SIZE));
  1128. size = len > m_blocksize - BLOCK_HDR_SIZE ? m_blocksize - BLOCK_HDR_SIZE : len;
  1129. RETURN_IF_ERROR_CLEANUP(m_file->Write(data, size));
  1130. data = (const char *)data + size;
  1131. len -= size;
  1132. }
  1133. m_file->Flush();
  1134. if (next != 0)
  1135. {
  1136. OP_ASSERT(next != pos);
  1137. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos));
  1138. RETURN_IF_ERROR_CLEANUP(WriteBlockHeader(m_file, 0, pos == orig_pos));
  1139. if (!Delete(next))
  1140. goto cleanup;
  1141. }
  1142. if (m_EndianCallback != NULL)
  1143. SwitchEndianInData(orig_data, orig_len);
  1144. return TRUE;
  1145. cleanup:
  1146. if (m_EndianCallback != NULL)
  1147. SwitchEndianInData(orig_data, orig_len);
  1148. return FALSE;
  1149. }
  1150. BOOL BlockStorage::Update(const void *data, int offset, int len, OpFileLength pos)
  1151. {
  1152. void *orig_data;
  1153. int old_size, write_size, orig_len;
  1154. OpFileLength next, orig_pos;
  1155. OP_STATUS rv = OpStatus::OK;
  1156. if (m_file == NULL)
  1157. return FALSE;
  1158. #ifdef _DEBUG
  1159. OP_ASSERT(!InTransaction() || !m_journal_invalid);
  1160. #endif
  1161. OP_ASSERT(IS_START_BLOCK(pos));
  1162. OP_ASSERT(!WaitingForGroupCommit());
  1163. orig_data = (void *)data;
  1164. orig_len = len;
  1165. orig_pos = pos;
  1166. if (m_EndianCallback != NULL)
  1167. SwitchEndianInData(orig_data, len);
  1168. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos + BLOCK_HDR_SIZE));
  1169. RETURN_IF_ERROR_CLEANUP(ReadInt32(m_file, &old_size));
  1170. if (old_size < offset)
  1171. goto cleanup;
  1172. write_size = m_blocksize;
  1173. next = 0;
  1174. if (old_size < offset + len)
  1175. {
  1176. if (InTransaction())
  1177. RETURN_IF_ERROR_CLEANUP(JournalBlock(pos));
  1178. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos + BLOCK_HDR_SIZE));
  1179. RETURN_IF_ERROR_CLEANUP(WriteInt32(m_file, offset + len));
  1180. }
  1181. if (offset >= m_blocksize - BLOCK_HDR_SIZE - 4)
  1182. {
  1183. offset -= m_blocksize - BLOCK_HDR_SIZE - 4;
  1184. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos));
  1185. RETURN_IF_ERROR_CLEANUP(ReadBlockHeader(m_file, &next));
  1186. while (offset >= m_blocksize - BLOCK_HDR_SIZE)
  1187. {
  1188. pos = next;
  1189. OP_ASSERT(IS_NOT_START_BLOCK(pos));
  1190. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(next));
  1191. RETURN_IF_ERROR_CLEANUP(ReadBlockHeader(m_file, &next));
  1192. offset -= m_blocksize - BLOCK_HDR_SIZE;
  1193. }
  1194. if (offset != 0)
  1195. {
  1196. pos = next;
  1197. OP_ASSERT(IS_NOT_START_BLOCK(pos));
  1198. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(next));
  1199. RETURN_IF_ERROR_CLEANUP(ReadBlockHeader(m_file, &next));
  1200. }
  1201. }
  1202. else {
  1203. write_size = len + offset > m_blocksize - BLOCK_HDR_SIZE - 4 ? m_blocksize - BLOCK_HDR_SIZE - 4 - offset : len;
  1204. if (InTransaction())
  1205. RETURN_IF_ERROR_CLEANUP(JournalBlock(pos));
  1206. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos + BLOCK_HDR_SIZE + 4 + offset));
  1207. RETURN_IF_ERROR_CLEANUP(m_file->Write(data, write_size));
  1208. data = (const char *)data + write_size;
  1209. len -= write_size;
  1210. write_size += offset + 4;
  1211. offset = 0;
  1212. if (len > 0)
  1213. {
  1214. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos));
  1215. RETURN_IF_ERROR_CLEANUP(ReadBlockHeader(m_file, &next));
  1216. }
  1217. }
  1218. if (offset != 0) // write to partially affected block
  1219. {
  1220. write_size = len + offset > m_blocksize - BLOCK_HDR_SIZE ? m_blocksize - BLOCK_HDR_SIZE - offset : len;
  1221. if (InTransaction())
  1222. RETURN_IF_ERROR_CLEANUP(JournalBlock(pos));
  1223. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos + BLOCK_HDR_SIZE + offset));
  1224. RETURN_IF_ERROR_CLEANUP(m_file->Write(data, write_size));
  1225. data = (const char *)data + write_size;
  1226. len -= write_size;
  1227. write_size += offset;
  1228. }
  1229. // pos ~ the previous block, next ~ the block to write / 0 to create one, offset == 0
  1230. while (len > 0)
  1231. {
  1232. if (next != 0)
  1233. {
  1234. pos = next;
  1235. if (InTransaction())
  1236. RETURN_IF_ERROR_CLEANUP(JournalBlock(pos));
  1237. }
  1238. else {
  1239. if ((pos = CreateBlock(pos, pos == orig_pos)) == 0)
  1240. goto cleanup;
  1241. }
  1242. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos));
  1243. RETURN_IF_ERROR_CLEANUP(ReadBlockHeader(m_file, &next));
  1244. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos + BLOCK_HDR_SIZE));
  1245. write_size = len > m_blocksize - BLOCK_HDR_SIZE ? m_blocksize - BLOCK_HDR_SIZE : len;
  1246. RETURN_IF_ERROR_CLEANUP(m_file->Write(data, write_size));
  1247. data = (const char *)data + write_size;
  1248. len -= write_size;
  1249. }
  1250. m_file->Flush();
  1251. if (m_EndianCallback != NULL)
  1252. SwitchEndianInData(orig_data, orig_len);
  1253. return TRUE;
  1254. cleanup:
  1255. if (m_EndianCallback != NULL)
  1256. SwitchEndianInData(orig_data, orig_len);
  1257. return FALSE;
  1258. }
  1259. BOOL BlockStorage::Update(int len, OpFileLength pos)
  1260. {
  1261. int size, old_size;
  1262. OpFileLength orig_pos, next;
  1263. if (m_file == NULL)
  1264. return FALSE;
  1265. #ifdef _DEBUG
  1266. OP_ASSERT(!InTransaction() || !m_journal_invalid);
  1267. #endif
  1268. OP_ASSERT(IS_START_BLOCK(pos));
  1269. OP_ASSERT(!WaitingForGroupCommit());
  1270. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos + BLOCK_HDR_SIZE), FALSE);
  1271. RETURN_VALUE_IF_ERROR(ReadInt32(m_file, &old_size), FALSE);
  1272. if (old_size < len)
  1273. return FALSE;
  1274. if (old_size == len)
  1275. return TRUE;
  1276. if (InTransaction())
  1277. RETURN_VALUE_IF_ERROR(JournalBlock(pos), FALSE);
  1278. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos + BLOCK_HDR_SIZE), FALSE);
  1279. RETURN_VALUE_IF_ERROR(WriteInt32(m_file, len), FALSE);
  1280. size = len > m_blocksize - BLOCK_HDR_SIZE - 4 ? m_blocksize - BLOCK_HDR_SIZE - 4 : len;
  1281. if (size > 0)
  1282. len -= size;
  1283. if (len / (m_blocksize - BLOCK_HDR_SIZE) == (old_size - size) / (m_blocksize - BLOCK_HDR_SIZE))
  1284. {
  1285. m_file->Flush();
  1286. return TRUE;
  1287. }
  1288. orig_pos = pos;
  1289. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos), FALSE);
  1290. RETURN_VALUE_IF_ERROR(ReadBlockHeader(m_file, &next), FALSE);
  1291. while (len > 0)
  1292. {
  1293. if (next == 0)
  1294. break;
  1295. pos = next;
  1296. OP_ASSERT(IS_NOT_START_BLOCK(next));
  1297. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos), FALSE);
  1298. RETURN_VALUE_IF_ERROR(ReadBlockHeader(m_file, &next), FALSE);
  1299. size = len > m_blocksize - BLOCK_HDR_SIZE ? m_blocksize - BLOCK_HDR_SIZE : len;
  1300. len -= size;
  1301. }
  1302. m_file->Flush();
  1303. if (next != 0)
  1304. {
  1305. // This is very dangerous. If you see this assert, break the program execution here and run away!
  1306. OP_ASSERT(next != pos);
  1307. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos), FALSE);
  1308. RETURN_VALUE_IF_ERROR(WriteBlockHeader(m_file, 0, pos == orig_pos), FALSE);
  1309. return Delete(next);
  1310. }
  1311. return TRUE;
  1312. }
  1313. BOOL BlockStorage::Delete(OpFileLength pos)
  1314. {
  1315. OpFileLength last_block_pos, next_block, file_length, bitfield_pos, min_bf;
  1316. OpFileLength orig_pos = pos;
  1317. int block_no;
  1318. unsigned char c;
  1319. BOOL last_block_deleted = FALSE;
  1320. if (m_file == NULL)
  1321. return FALSE;
  1322. #ifdef _DEBUG
  1323. OP_ASSERT(!InTransaction() || !m_journal_invalid);
  1324. #endif
  1325. //OP_ASSERT(IS_START_BLOCK(pos)); Allow chopping off the end of a chain from Update
  1326. OP_ASSERT(IS_NORMAL_BLOCK(pos));
  1327. OP_ASSERT(m_reserved_area == 0 && m_reserved_size == 0 && m_reserved_deleted == INVALID_FILE_LENGTH);
  1328. OP_ASSERT(!WaitingForGroupCommit());
  1329. m_file->Flush();
  1330. RETURN_VALUE_IF_ERROR(m_file->GetFileLength(&file_length), FALSE);
  1331. last_block_pos = file_length - m_blocksize;
  1332. if (m_freeblock == INVALID_FILE_LENGTH)
  1333. {
  1334. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(0), FALSE);
  1335. RETURN_VALUE_IF_ERROR(ReadOFL(m_file, &m_freeblock), FALSE);
  1336. }
  1337. min_bf = file_length;
  1338. while (pos != 0)
  1339. {
  1340. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos), FALSE);
  1341. RETURN_VALUE_IF_ERROR(ReadBlockHeader(m_file, &next_block), FALSE);
  1342. //OP_ASSERT(IS_NOT_START_BLOCK(next_block)); Allow deletion of "Append" chains
  1343. OP_ASSERT(IS_NORMAL_BLOCK(pos));
  1344. bitfield_pos = BITFIELD_POS(pos);
  1345. block_no = (int)((pos - bitfield_pos) / m_blocksize - 1);
  1346. if (bitfield_pos < min_bf)
  1347. min_bf = bitfield_pos;
  1348. if (InTransaction())
  1349. {
  1350. RETURN_VALUE_IF_ERROR(JournalBlock(bitfield_pos), FALSE);
  1351. // journalling the deleted block isn't really necessary here, but let's rather do it now then in CreateBlock
  1352. RETURN_VALUE_IF_ERROR(JournalBlock(pos), FALSE);
  1353. }
  1354. // NB! Optimize this later by using a cached bitfield for checking if
  1355. // a block is deleted in IsStartBlock(). (roarl)
  1356. if (pos == orig_pos) {
  1357. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos), FALSE);
  1358. RETURN_VALUE_IF_ERROR(WriteBlockHeader(m_file, next_block, FALSE), FALSE);
  1359. }
  1360. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(bitfield_pos + (block_no >> 3)), FALSE);
  1361. RETURN_VALUE_IF_ERROR(ReadFully(m_file, &c, 1), FALSE);
  1362. OP_ASSERT((c & (1 << (block_no & 7))) == 0);
  1363. c |= 1 << (block_no & 7);
  1364. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(bitfield_pos + (block_no >> 3)), FALSE);
  1365. RETURN_VALUE_IF_ERROR(m_file->Write(&c, 1), FALSE);
  1366. last_block_deleted |= (pos >= last_block_pos);
  1367. pos = next_block;
  1368. }
  1369. if ((m_freeblock == 0 || m_freeblock > min_bf) && min_bf < file_length)
  1370. {
  1371. m_freeblock = min_bf;
  1372. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(0), FALSE);
  1373. RETURN_VALUE_IF_ERROR(WriteOFL(m_file, m_freeblock), FALSE);
  1374. }
  1375. m_file->Flush();
  1376. if (last_block_deleted)
  1377. RETURN_VALUE_IF_ERROR(Truncate(), FALSE);
  1378. return TRUE;
  1379. }
  1380. BOOL BlockStorage::WriteUserHeader(unsigned offset, const void *data, int len, int disk_len, int count)
  1381. {
  1382. int i;
  1383. char value[16]; /* ARRAY OK 2010-09-24 roarl */
  1384. #ifdef _DEBUG
  1385. OP_ASSERT(!InTransaction() || !m_journal_invalid);
  1386. #endif
  1387. OP_ASSERT(count >= 1);
  1388. OP_ASSERT(disk_len >= 0);
  1389. OP_ASSERT(disk_len <= 16); // integers longer than 128 bits are not supported
  1390. OP_ASSERT((disk_len == 0 && len * count <= m_blocksize - FILE_HDR_SIZE) ||
  1391. (disk_len != 0 && disk_len * count <= m_blocksize - FILE_HDR_SIZE)); // user header doesn't fit to the block
  1392. OP_ASSERT(!WaitingForGroupCommit());
  1393. if (m_file == NULL ||
  1394. (disk_len == 0 && len * count > m_blocksize - FILE_HDR_SIZE) ||
  1395. (disk_len != 0 && disk_len * count > m_blocksize - FILE_HDR_SIZE))
  1396. return FALSE;
  1397. if (InTransaction())
  1398. RETURN_VALUE_IF_ERROR(JournalBlock(0), FALSE);
  1399. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(FILE_HDR_SIZE + offset), FALSE);
  1400. if (disk_len == 0)
  1401. return OpStatus::IsSuccess(m_file->Write(data, len * count));
  1402. for (i = 0; i < count; ++i)
  1403. {
  1404. op_memset(value, 0, sizeof(value));
  1405. #ifdef OPERA_BIG_ENDIAN
  1406. if (disk_len >= len)
  1407. op_memcpy(value + disk_len - len, (char *)data + i * len, len);
  1408. else
  1409. op_memcpy(value, (char *)data + i * len + (len - disk_len), disk_len);
  1410. #else
  1411. op_memcpy(value, (char *)data + i * len, disk_len >= len ? len : disk_len);
  1412. #endif
  1413. if (!IsNativeEndian())
  1414. SwitchEndian(value, disk_len);
  1415. RETURN_VALUE_IF_ERROR(m_file->Write(value, disk_len), FALSE);
  1416. }
  1417. return TRUE;
  1418. }
  1419. BOOL BlockStorage::ReadUserHeader(unsigned offset, void *data, int len, int disk_len, int count)
  1420. {
  1421. int i;
  1422. char value[16]; /* ARRAY OK 2010-09-24 roarl */
  1423. OP_ASSERT(count >= 1);
  1424. OP_ASSERT(disk_len >= 0);
  1425. OP_ASSERT(disk_len <= 16); // integers longer than 128 bits are not supported
  1426. OP_ASSERT((disk_len == 0 && len * count <= m_blocksize - FILE_HDR_SIZE) ||
  1427. (disk_len != 0 && disk_len * count <= m_blocksize - FILE_HDR_SIZE)); // user header doesn't fit to the block
  1428. if (m_file == NULL ||
  1429. (disk_len == 0 && len * count > m_blocksize - FILE_HDR_SIZE) ||
  1430. (disk_len != 0 && disk_len * count > m_blocksize - FILE_HDR_SIZE))
  1431. return FALSE;
  1432. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(FILE_HDR_SIZE + offset), FALSE);
  1433. if (disk_len == 0)
  1434. return OpStatus::IsSuccess(ReadFully(m_file, data, len * count));
  1435. for (i = 0; i < count; ++i)
  1436. {
  1437. op_memset(value, 0, sizeof(value));
  1438. RETURN_VALUE_IF_ERROR(ReadFully(m_file, value, disk_len), FALSE);
  1439. if (!IsNativeEndian())
  1440. SwitchEndian(value, disk_len);
  1441. #ifdef OPERA_BIG_ENDIAN
  1442. if (disk_len >= len)
  1443. op_memcpy((char *)data + i * len, value + disk_len - len, len);
  1444. else
  1445. op_memcpy((char *)data + i * len + (len - disk_len), value, disk_len);
  1446. #else
  1447. op_memcpy((char *)data + i * len, value, disk_len >= len ? len : disk_len);
  1448. #endif
  1449. }
  1450. return TRUE;
  1451. }
  1452. OpFileLength BlockStorage::Append(const void *data, int len, OpFileLength pos)
  1453. {
  1454. void *orig_data;
  1455. int size, orig_len;
  1456. INT32 old_size;
  1457. int old_block_size;
  1458. OP_STATUS rv = OpStatus::OK;
  1459. if (m_file == NULL)
  1460. return 0;
  1461. #ifdef _DEBUG
  1462. OP_ASSERT(!InTransaction() || !m_journal_invalid);
  1463. #endif
  1464. OP_ASSERT(!WaitingForGroupCommit());
  1465. if (pos == 0)
  1466. old_size = 0;
  1467. else {
  1468. OP_ASSERT(IS_START_BLOCK(pos));
  1469. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos + BLOCK_HDR_SIZE), 0);
  1470. RETURN_VALUE_IF_ERROR(ReadInt32(m_file, &old_size), 0);
  1471. }
  1472. orig_data = (void *)data;
  1473. orig_len = len;
  1474. if (m_EndianCallback != NULL)
  1475. SwitchEndianInData(orig_data, len);
  1476. old_block_size = old_size % (m_blocksize - BLOCK_HDR_SIZE - 4);
  1477. if (old_block_size != 0)
  1478. {
  1479. size = len + old_block_size > m_blocksize - BLOCK_HDR_SIZE - 4 ? m_blocksize - BLOCK_HDR_SIZE - 4 - old_block_size : len;
  1480. if (InTransaction())
  1481. RETURN_IF_ERROR_CLEANUP(JournalBlock(pos));
  1482. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos + BLOCK_HDR_SIZE));
  1483. RETURN_IF_ERROR_CLEANUP(WriteInt32(m_file, old_size + size));
  1484. if (size > 0) {
  1485. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos + BLOCK_HDR_SIZE + 4 + old_block_size));
  1486. RETURN_IF_ERROR_CLEANUP(m_file->Write(data, size));
  1487. data = (const char *)data + size;
  1488. len -= size;
  1489. old_size += size;
  1490. }
  1491. }
  1492. while (len > 0)
  1493. {
  1494. if ((pos = CreateBlock(pos, TRUE, TRUE)) == 0)
  1495. goto cleanup;
  1496. size = len > m_blocksize - BLOCK_HDR_SIZE - 4 ? m_blocksize - BLOCK_HDR_SIZE - 4 : len;
  1497. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos + BLOCK_HDR_SIZE));
  1498. RETURN_IF_ERROR_CLEANUP(WriteInt32(m_file, old_size + size));
  1499. RETURN_IF_ERROR_CLEANUP(m_file->Write(data, size));
  1500. data = (const char *)data + size;
  1501. len -= size;
  1502. old_size += size;
  1503. }
  1504. m_file->Flush();
  1505. if (m_EndianCallback != NULL)
  1506. SwitchEndianInData(orig_data, orig_len);
  1507. return pos;
  1508. cleanup:
  1509. if (m_EndianCallback != NULL)
  1510. SwitchEndianInData(orig_data, orig_len);
  1511. return 0;
  1512. }
  1513. BOOL BlockStorage::ReadApnd(void *data, int len, OpFileLength pos)
  1514. {
  1515. void *orig_data;
  1516. int size, orig_len;
  1517. register int size_available;
  1518. OpFileLength next;
  1519. INT32 maxlen;
  1520. if (m_file == NULL || len < 0)
  1521. return FALSE;
  1522. OP_ASSERT(IS_START_BLOCK(pos));
  1523. orig_data = data;
  1524. orig_len = len;
  1525. if (len == 0)
  1526. return TRUE;
  1527. m_file->Flush();
  1528. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos), FALSE);
  1529. RETURN_VALUE_IF_ERROR(ReadBlockHeader(m_file, &next), FALSE);
  1530. RETURN_VALUE_IF_ERROR(ReadInt32(m_file, &maxlen), FALSE);
  1531. if (len > maxlen)
  1532. {
  1533. OP_ASSERT(0);
  1534. return FALSE;
  1535. }
  1536. size = maxlen % (m_blocksize - BLOCK_HDR_SIZE - 4);
  1537. if (size == 0)
  1538. size = m_blocksize - BLOCK_HDR_SIZE - 4;
  1539. if (size > len)
  1540. size = len;
  1541. data = (char *)data + len - size;
  1542. size_available = maxlen % (m_blocksize - BLOCK_HDR_SIZE - 4);
  1543. if (size < size_available)
  1544. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos + BLOCK_HDR_SIZE + 4 + size_available - size), FALSE);
  1545. RETURN_VALUE_IF_ERROR(ReadFully(m_file, data, size), FALSE);
  1546. len -= size;
  1547. size = m_blocksize - BLOCK_HDR_SIZE - 4;
  1548. while (len > 0)
  1549. {
  1550. if (next == 0) // not enough data in the file
  1551. return FALSE;
  1552. pos = next;
  1553. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos), FALSE);
  1554. RETURN_VALUE_IF_ERROR(ReadBlockHeader(m_file, &next), FALSE);
  1555. if (size > len)
  1556. size = len;
  1557. data = (char *)data - size;
  1558. size_available = m_blocksize - BLOCK_HDR_SIZE - 4;
  1559. if (size < size_available)
  1560. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos + BLOCK_HDR_SIZE + 4 + size_available - size), FALSE);
  1561. else
  1562. RETURN_VALUE_IF_ERROR(ReadInt32(m_file, &maxlen), FALSE); // to move the file pointer
  1563. RETURN_VALUE_IF_ERROR(ReadFully(m_file, data, size), FALSE);
  1564. len -= size;
  1565. }
  1566. if (m_EndianCallback != NULL)
  1567. SwitchEndianInData(orig_data, orig_len);
  1568. return TRUE;
  1569. }
  1570. OpFileLength BlockStorage::CreateBlock(OpFileLength current_block, BOOL current_start_block, BOOL append_mode)
  1571. {
  1572. OpFileLength block_pos;
  1573. BOOL start_block = current_block == 0;
  1574. OP_ASSERT(!WaitingForGroupCommit());
  1575. if (m_freeblock == INVALID_FILE_LENGTH)
  1576. {
  1577. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(0), 0);
  1578. RETURN_VALUE_IF_ERROR(ReadOFL(m_file, &m_freeblock), 0);
  1579. }
  1580. if (m_freeblock != 0)
  1581. {
  1582. if ((block_pos = GetFreeBlock(TRUE)) == 0)
  1583. return 0;
  1584. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(block_pos), 0);
  1585. }
  1586. else {
  1587. if (m_reserved_area != 0)
  1588. {
  1589. OP_ASSERT(0); // mixing Reserve and Write/Update doesn't make sense
  1590. if (m_reserved_size != 0)
  1591. {
  1592. RETURN_VALUE_IF_ERROR(m_file->SetFileLength(m_reserved_area), 0);
  1593. }
  1594. m_reserved_area = 0;
  1595. m_reserved_size = 0;
  1596. }
  1597. m_file->Flush();
  1598. RETURN_VALUE_IF_ERROR(m_file->GetFileLength(&block_pos), 0);
  1599. // This is very dangerous. If you see this assert, break the program execution here and run away!
  1600. OP_ASSERT(current_block < block_pos);
  1601. if (IS_BITFIELD_BLOCK(block_pos))
  1602. { // create a bitfield for deleted blocks
  1603. int fi;
  1604. OpFileLength fill = 0;
  1605. RETURN_VALUE_IF_ERROR(m_file->SetFileLength(block_pos + m_blocksize * 2), 0);
  1606. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(block_pos), 0);
  1607. for (fi = m_blocksize / sizeof(fill); fi > 0; --fi)
  1608. RETURN_VALUE_IF_ERROR(m_file->Write(&fill, sizeof(fill)), 0);
  1609. if (m_blocksize % sizeof(fill) != 0)
  1610. RETURN_VALUE_IF_ERROR(m_file->Write(&fill, m_blocksize % sizeof(fill)), 0);
  1611. block_pos += m_blocksize;
  1612. }
  1613. else
  1614. RETURN_VALUE_IF_ERROR(m_file->SetFileLength(block_pos + m_blocksize), 0);
  1615. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(block_pos), 0);
  1616. }
  1617. if (append_mode)
  1618. {
  1619. RETURN_VALUE_IF_ERROR(WriteBlockHeader(m_file, current_block, TRUE), 0);
  1620. }
  1621. else
  1622. {
  1623. RETURN_VALUE_IF_ERROR(WriteBlockHeader(m_file, 0, start_block), 0); // next block is 0
  1624. }
  1625. if (current_block != 0 && !append_mode)
  1626. {
  1627. if (InTransaction())
  1628. RETURN_VALUE_IF_ERROR(JournalBlock(current_block), 0);
  1629. // This is very dangerous. If you see this assert, break the program execution here and run away!
  1630. OP_ASSERT(block_pos != current_block);
  1631. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(current_block), 0);
  1632. RETURN_VALUE_IF_ERROR(WriteBlockHeader(m_file, block_pos, current_start_block), 0);
  1633. }
  1634. m_file->Flush();
  1635. return block_pos;
  1636. }
  1637. // return a block from the list of deleted blocks
  1638. // update_file - GetFreeBlock is called from Update or Write via CreateBlock, !update_file - GetFreeBlock is called from Reserve
  1639. // m_freeblock must be > 0 upon a call of this method, therefore at least one non-empty bitfield exists
  1640. // m_reserved_deleted must be > 0 or -1
  1641. // if update_file, bit field pointed by m_freeblock is modified directly, m_freeblock may be updated to the next non-empty bitfield
  1642. // if !update_file, m_reserved_deleted is updated to point to the next free block or 0 on EOF (then m_freeblock would also 0)
  1643. OpFileLength BlockStorage::GetFreeBlock(BOOL update_file)
  1644. {
  1645. unsigned char *block_buf = NULL;
  1646. unsigned char c, tc;
  1647. int i, j, k;
  1648. BOOL more_exist;
  1649. OpFileLength fsize, block_pos, bitfield_pos;
  1650. unsigned block_no;
  1651. OP_STATUS rv = OpStatus::OK;
  1652. OP_ASSERT(m_freeblock != 0 && m_freeblock != INVALID_FILE_LENGTH);
  1653. OP_ASSERT(!update_file || m_reserved_deleted == INVALID_FILE_LENGTH);
  1654. OP_ASSERT(!WaitingForGroupCommit());
  1655. if (m_reserved_deleted == INVALID_FILE_LENGTH)
  1656. {
  1657. bitfield_pos = m_freeblock;
  1658. block_no = 0;
  1659. }
  1660. else {
  1661. bitfield_pos = BITFIELD_POS(m_reserved_deleted);
  1662. block_no = (int)((m_reserved_deleted - bitfield_pos) / m_blocksize - 1);
  1663. }
  1664. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(bitfield_pos), 0);
  1665. if ((block_buf = OP_NEWA(unsigned char, m_blocksize)) != NULL)
  1666. {
  1667. RETURN_IF_ERROR_CLEANUP(ReadFully(m_file, block_buf, m_blocksize));
  1668. // find the first available deleted block, because it isn't known yet
  1669. if (m_reserved_deleted == INVALID_FILE_LENGTH)
  1670. {
  1671. i = 0;
  1672. j = 0;
  1673. while (i < m_blocksize && block_buf[i] == 0)
  1674. ++i;
  1675. OP_ASSERT(i < m_blocksize);
  1676. if (i >= m_blocksize)
  1677. goto cleanup;
  1678. c = block_buf[i];
  1679. while (((1 << j) & c) == 0)
  1680. ++j;
  1681. block_no = i * 8 + j;
  1682. block_pos = m_freeblock + ((OpFileLength)i * 8 + j) * m_blocksize + m_blocksize;
  1683. }
  1684. else {
  1685. i = block_no >> 3;
  1686. j = block_no & 7;
  1687. c = block_buf[i];
  1688. block_pos = m_reserved_deleted;
  1689. }
  1690. c &= ((unsigned char)0xFF) << (j + 1);
  1691. more_exist = c != 0; // this means more in the same bitfield
  1692. k = i;
  1693. if (!more_exist)
  1694. {
  1695. ++k;
  1696. while (k < m_blocksize && block_buf[k] == 0)
  1697. ++k;
  1698. if (k < m_blocksize)
  1699. {
  1700. more_exist = TRUE;
  1701. j = 0;
  1702. while (((1 << j) & block_buf[k]) == 0)
  1703. ++j;
  1704. }
  1705. }
  1706. else {
  1707. do
  1708. ++j;
  1709. while (((1 << j) & c) == 0);
  1710. }
  1711. if (InTransaction())
  1712. RETURN_IF_ERROR_CLEANUP(JournalBlock(bitfield_pos));
  1713. if (update_file)
  1714. {
  1715. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(bitfield_pos + i));
  1716. RETURN_IF_ERROR_CLEANUP(m_file->Write(&c, 1));
  1717. }
  1718. if (!more_exist) // need to update m_freeblock to point to the next non-empty bitfield
  1719. {
  1720. m_file->Flush();
  1721. RETURN_IF_ERROR_CLEANUP(m_file->GetFileLength(&fsize));
  1722. if (update_file && InTransaction()) // otherwise journalled allready
  1723. RETURN_IF_ERROR_CLEANUP(JournalBlock(0));
  1724. m_freeblock += DISTANCE_BETWEEN_BITFIELDS;
  1725. while (m_freeblock < fsize)
  1726. {
  1727. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(m_freeblock));
  1728. RETURN_IF_ERROR_CLEANUP(ReadFully(m_file, block_buf, m_blocksize));
  1729. for (i = 0; i < m_blocksize; ++i)
  1730. if (block_buf[i] != 0)
  1731. break;
  1732. if (i < m_blocksize)
  1733. break;
  1734. m_freeblock += DISTANCE_BETWEEN_BITFIELDS;
  1735. }
  1736. if (m_freeblock >= fsize)
  1737. {
  1738. m_freeblock = 0;
  1739. if (!update_file)
  1740. m_reserved_deleted = 0;
  1741. }
  1742. else if (!update_file)
  1743. {
  1744. j = 0;
  1745. while (((1 << j) & block_buf[i]) == 0)
  1746. ++j;
  1747. m_reserved_deleted = m_freeblock + ((OpFileLength)i * 8 + j) * m_blocksize + m_blocksize;
  1748. }
  1749. OP_DELETEA(block_buf);
  1750. if (update_file)
  1751. {
  1752. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(0), 0);
  1753. RETURN_VALUE_IF_ERROR(WriteOFL(m_file, m_freeblock), 0);
  1754. }
  1755. }
  1756. else {
  1757. if (!update_file)
  1758. m_reserved_deleted = m_freeblock + ((OpFileLength)k * 8 + j) * m_blocksize + m_blocksize;
  1759. OP_DELETEA(block_buf);
  1760. }
  1761. return block_pos;
  1762. }
  1763. // fallback if we couldn't allocate the buffer
  1764. // find the first available deleted block, because it isn't known yet
  1765. if (m_reserved_deleted == INVALID_FILE_LENGTH)
  1766. {
  1767. i = 0;
  1768. j = 0;
  1769. do {
  1770. RETURN_VALUE_IF_ERROR(ReadFully(m_file, &c, 1), 0);
  1771. if (c != 0)
  1772. break;
  1773. ++i;
  1774. } while (i < m_blocksize);
  1775. OP_ASSERT(i < m_blocksize);
  1776. while (((1 << j) & c) == 0)
  1777. ++j;
  1778. block_no = i * 8 + j;
  1779. block_pos = m_freeblock + ((OpFileLength)i * 8 + j) * m_blocksize + m_blocksize;
  1780. }
  1781. else {
  1782. i = block_no >> 3;
  1783. j = block_no & 7;
  1784. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(bitfield_pos + i), 0);
  1785. RETURN_VALUE_IF_ERROR(ReadFully(m_file, &c, 1), 0);
  1786. block_pos = m_reserved_deleted;
  1787. }
  1788. c &= ((unsigned char)0xFF) << (j + 1);
  1789. more_exist = c != 0; // this means more in the same bitfield
  1790. k = i;
  1791. if (!more_exist)
  1792. {
  1793. ++k;
  1794. if (k < m_blocksize)
  1795. {
  1796. do {
  1797. RETURN_VALUE_IF_ERROR(ReadFully(m_file, &tc, 1), 0);
  1798. if (tc != 0)
  1799. break;
  1800. ++k;
  1801. } while (k < m_blocksize);
  1802. if (k < m_blocksize)
  1803. {
  1804. more_exist = TRUE;
  1805. j = 0;
  1806. while (((1 << j) & tc) == 0)
  1807. ++j;
  1808. }
  1809. }
  1810. }
  1811. else {
  1812. do
  1813. ++j;
  1814. while (((1 << j) & c) == 0);
  1815. }
  1816. if (InTransaction())
  1817. RETURN_VALUE_IF_ERROR(JournalBlock(bitfield_pos), 0);
  1818. if (update_file)
  1819. {
  1820. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(bitfield_pos + i), 0);
  1821. RETURN_VALUE_IF_ERROR(m_file->Write(&c, 1), 0);
  1822. }
  1823. if (!more_exist) // need to update m_freeblock to point to the next non-empty bitfield
  1824. {
  1825. m_file->Flush();
  1826. RETURN_VALUE_IF_ERROR(m_file->GetFileLength(&fsize), 0);
  1827. if (update_file && InTransaction()) // otherwise journalled allready
  1828. RETURN_VALUE_IF_ERROR(JournalBlock(0), 0);
  1829. m_freeblock += DISTANCE_BETWEEN_BITFIELDS;
  1830. while (m_freeblock < fsize)
  1831. {
  1832. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(m_freeblock), 0);
  1833. for (i = 0; i < m_blocksize; ++i)
  1834. {
  1835. RETURN_VALUE_IF_ERROR(ReadFully(m_file, &c, 1), 0);
  1836. if (c != 0)
  1837. break;
  1838. }
  1839. if (i < m_blocksize)
  1840. break;
  1841. m_freeblock += DISTANCE_BETWEEN_BITFIELDS;
  1842. }
  1843. if (m_freeblock >= fsize)
  1844. {
  1845. m_freeblock = 0;
  1846. if (!update_file)
  1847. m_reserved_deleted = 0;
  1848. }
  1849. else if (!update_file)
  1850. {
  1851. j = 0;
  1852. while (((1 << j) & c) == 0)
  1853. ++j;
  1854. m_reserved_deleted = m_freeblock + ((OpFileLength)i * 8 + j) * m_blocksize + m_blocksize;
  1855. }
  1856. if (update_file)
  1857. {
  1858. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(0), 0);
  1859. RETURN_VALUE_IF_ERROR(WriteOFL(m_file, m_freeblock), 0);
  1860. }
  1861. }
  1862. else {
  1863. if (!update_file)
  1864. m_reserved_deleted = m_freeblock + ((OpFileLength)k * 8 + j) * m_blocksize + m_blocksize;
  1865. }
  1866. return block_pos;
  1867. cleanup:
  1868. OP_DELETEA(block_buf);
  1869. return 0;
  1870. }
  1871. // when Delete calls Truncate, there is at least one free block and at least one block to truncate
  1872. OP_STATUS BlockStorage::Truncate(void)
  1873. {
  1874. OpFileLength trunc_block, last_block, bitfield_pos;
  1875. int i, j;
  1876. unsigned char *block_buf = NULL;
  1877. unsigned char c;
  1878. OP_STATUS rv = OpStatus::OK;
  1879. OP_ASSERT(!WaitingForGroupCommit());
  1880. if (m_freeblock == INVALID_FILE_LENGTH)
  1881. {
  1882. RETURN_IF_ERROR(m_file->SetFilePos(0));
  1883. RETURN_IF_ERROR(ReadOFL(m_file, &m_freeblock));
  1884. }
  1885. m_file->Flush();
  1886. RETURN_IF_ERROR(m_file->GetFileLength(&last_block));
  1887. last_block -= m_blocksize;
  1888. bitfield_pos = BITFIELD_POS(last_block);
  1889. trunc_block = last_block;
  1890. if ((block_buf = OP_NEWA(unsigned char, m_blocksize)) != NULL)
  1891. {
  1892. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(bitfield_pos));
  1893. do {
  1894. RETURN_IF_ERROR_CLEANUP(ReadFully(m_file, block_buf, m_blocksize));
  1895. i = (int)((trunc_block - bitfield_pos - 1) / m_blocksize);
  1896. while (i >= 0 && (block_buf[i >> 3] & (1 << (i & 7))) != 0)
  1897. {
  1898. trunc_block -= m_blocksize;
  1899. --i;
  1900. }
  1901. if (i < 0)
  1902. {
  1903. trunc_block -= m_blocksize;
  1904. if (trunc_block > m_freeblock)
  1905. {
  1906. bitfield_pos -= DISTANCE_BETWEEN_BITFIELDS;
  1907. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(bitfield_pos));
  1908. i = 8 * m_blocksize - 1;
  1909. }
  1910. else {
  1911. m_freeblock = 0;
  1912. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(0));
  1913. RETURN_IF_ERROR_CLEANUP(WriteOFL(m_file, m_freeblock));
  1914. break;
  1915. }
  1916. }
  1917. else {
  1918. block_buf[i >> 3] &= ((unsigned char)0xFF) >> (8 - (i & 7));
  1919. op_memset(block_buf + (i >> 3) + 1, 0, m_blocksize - (i >> 3) - 1);
  1920. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(bitfield_pos + (i >> 3)));
  1921. RETURN_IF_ERROR_CLEANUP(m_file->Write(block_buf + (i >> 3), m_blocksize - (i >> 3)));
  1922. i >>= 3;
  1923. // adjust m_freeblock
  1924. while (i >= 0 && block_buf[i] == 0)
  1925. --i;
  1926. // if m_freeblock < bitfield_pos, there are more free blocks
  1927. if (i < 0 && bitfield_pos <= m_freeblock)
  1928. {
  1929. m_freeblock = 0;
  1930. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(0));
  1931. RETURN_IF_ERROR_CLEANUP(WriteOFL(m_file, m_freeblock));
  1932. }
  1933. break;
  1934. }
  1935. } while (1);
  1936. OP_DELETEA(block_buf);
  1937. return m_file->SetFileLength(trunc_block + m_blocksize);
  1938. }
  1939. // fallback for out of memory
  1940. do {
  1941. i = (int)((trunc_block - bitfield_pos - 1) / m_blocksize);
  1942. do {
  1943. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(bitfield_pos + (i >> 3)));
  1944. RETURN_IF_ERROR_CLEANUP(ReadFully(m_file, &c, 1));
  1945. if ((c & (1 << (i & 7))) == 0)
  1946. break;
  1947. trunc_block -= m_blocksize;
  1948. --i;
  1949. } while (i >= 0);
  1950. if (i < 0)
  1951. {
  1952. trunc_block -= m_blocksize;
  1953. if (trunc_block > m_freeblock)
  1954. {
  1955. bitfield_pos -= DISTANCE_BETWEEN_BITFIELDS;
  1956. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(bitfield_pos));
  1957. i = 8 * m_blocksize - 1;
  1958. }
  1959. else {
  1960. m_freeblock = 0;
  1961. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(0));
  1962. RETURN_IF_ERROR_CLEANUP(WriteOFL(m_file, m_freeblock));
  1963. break;
  1964. }
  1965. }
  1966. else {
  1967. c &= ((unsigned char)0xFF) >> (8 - (i & 7));
  1968. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(bitfield_pos + (i >> 3)));
  1969. RETURN_IF_ERROR_CLEANUP(m_file->Write(&c, 1));
  1970. c = 0;
  1971. for (j = 1; j < m_blocksize - (i >> 3); ++j)
  1972. RETURN_IF_ERROR_CLEANUP(m_file->Write(&c, 1));
  1973. i >>= 3;
  1974. // adjust m_freeblock
  1975. do {
  1976. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(bitfield_pos + i));
  1977. RETURN_IF_ERROR_CLEANUP(ReadFully(m_file, &c, 1));
  1978. if (c != 0)
  1979. break;
  1980. --i;
  1981. } while (i >= 0);
  1982. if (i < 0 && bitfield_pos <= m_freeblock)
  1983. {
  1984. m_freeblock = 0;
  1985. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(0));
  1986. RETURN_IF_ERROR_CLEANUP(WriteOFL(m_file, m_freeblock));
  1987. }
  1988. break;
  1989. }
  1990. } while (1);
  1991. return m_file->SetFileLength(trunc_block + m_blocksize);
  1992. cleanup:
  1993. OP_DELETEA(block_buf);
  1994. OpStatus::Ignore(m_file->SetFileLength(trunc_block + m_blocksize));
  1995. return rv;
  1996. }
  1997. OP_STATUS BlockStorage::JournalBlock(OpFileLength pos)
  1998. {
  1999. int block_no;
  2000. unsigned char in_journal;
  2001. char *blockbuf = NULL;
  2002. unsigned char *compressed_buf = NULL;
  2003. int c_size;
  2004. OP_STATUS rv;
  2005. OP_ASSERT(AT_BLOCK_BOUNDARY(pos));
  2006. block_no = (int)(pos / m_blocksize);
  2007. if (block_no >= m_transaction_blocks) // newly created blocks aren't journalled
  2008. return OpStatus::OK;
  2009. RETURN_IF_ERROR(m_transaction->SetFilePos(JOURNAL_HDR_SIZE + (block_no >> 3)));
  2010. RETURN_IF_ERROR(ReadFully(m_transaction, &in_journal, 1));
  2011. if (in_journal & (1 << (block_no & 7))) // block is already journalled
  2012. return OpStatus::OK;
  2013. RETURN_OOM_IF_NULL(compressed_buf = OP_NEWA(unsigned char, ((3 * m_blocksize) >> 1) + 8));
  2014. if ((blockbuf = OP_NEWA(char, m_blocksize)) == NULL)
  2015. {
  2016. OP_DELETEA(compressed_buf);
  2017. return OpStatus::ERR_NO_MEMORY;
  2018. }
  2019. RETURN_IF_ERROR_CLEANUP(m_transaction->SetFilePos(0, SEEK_FROM_END));
  2020. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos));
  2021. RETURN_IF_ERROR_CLEANUP(WriteOFL(m_transaction, pos));
  2022. if (OpStatus::IsSuccess(rv = ReadFully(m_file, blockbuf, m_blocksize)))
  2023. {
  2024. c_size = m_journal_compressor.Compress(compressed_buf, blockbuf, m_blocksize);
  2025. OP_ASSERT(c_size > 0);
  2026. OP_ASSERT(c_size <= ((3 * m_blocksize) >> 1) + 8);
  2027. RETURN_IF_ERROR_CLEANUP(WriteInt32(m_transaction, c_size));
  2028. RETURN_IF_ERROR_CLEANUP(m_transaction->Write(compressed_buf, c_size));
  2029. }
  2030. OP_DELETEA(blockbuf);
  2031. OP_DELETEA(compressed_buf);
  2032. RETURN_IF_ERROR(m_transaction->SetFilePos(JOURNAL_HDR_SIZE + (block_no >> 3)));
  2033. in_journal |= (1 << (block_no & 7));
  2034. RETURN_IF_ERROR(m_transaction->Write(&in_journal, 1));
  2035. rv = m_transaction->Flush();
  2036. RETURN_IF_ERROR(m_transaction->SetFilePos(0));
  2037. return rv;
  2038. cleanup:
  2039. OP_DELETEA(blockbuf);
  2040. OP_DELETEA(compressed_buf);
  2041. return rv;
  2042. }
  2043. void BlockStorage::SwitchEndianInData(void *data, int size)
  2044. {
  2045. unsigned char *ptr = (unsigned char *)data;
  2046. register int processed;
  2047. while (size > 0)
  2048. {
  2049. if ((processed = m_EndianCallback(ptr, size, m_callback_arg)) <= 0)
  2050. return;
  2051. ptr += processed;
  2052. size -= processed;
  2053. }
  2054. }
  2055. #include "modules/util/opfile/opfile.h"
  2056. OP_BOOLEAN BlockStorage::FileExists(const uni_char *name, OpFileFolder folder)
  2057. {
  2058. OpFile file;
  2059. BOOL exists;
  2060. RETURN_IF_ERROR(file.Construct(name, folder));
  2061. RETURN_IF_ERROR(file.Exists(exists));
  2062. return exists ? OpBoolean::IS_TRUE : OpBoolean::IS_FALSE;
  2063. }
  2064. OP_BOOLEAN BlockStorage::DeleteFile(const uni_char *name, OpFileFolder folder)
  2065. {
  2066. OpFile file;
  2067. BOOL exists;
  2068. RETURN_IF_ERROR(file.Construct(name, folder));
  2069. RETURN_IF_ERROR(file.Exists(exists));
  2070. if (exists)
  2071. {
  2072. OP_STATUS status = file.Delete();
  2073. if (status == OpStatus::ERR_FILE_NOT_FOUND)
  2074. exists = FALSE;
  2075. else if (OpStatus::IsError(status))
  2076. return status;
  2077. }
  2078. return exists ? OpBoolean::IS_TRUE : OpBoolean::IS_FALSE;
  2079. }
  2080. OP_BOOLEAN BlockStorage::DirectoryEmpty(const uni_char *name, OpFileFolder folder)
  2081. {
  2082. OpFolderLister *fl;
  2083. RETURN_OOM_IF_NULL(fl = OpFile::GetFolderLister(folder, UNI_L("*"), name));
  2084. while (fl->Next())
  2085. {
  2086. if (fl->IsFolder() &&
  2087. (uni_strcmp(fl->GetFileName(), UNI_L(".")) == 0 || uni_strcmp(fl->GetFileName(), UNI_L("..")) == 0))
  2088. continue;
  2089. OP_DELETE(fl);
  2090. return OpBoolean::IS_FALSE;
  2091. }
  2092. OP_DELETE(fl);
  2093. return OpBoolean::IS_TRUE;
  2094. }
  2095. OP_STATUS BlockStorage::RenameFile(const uni_char *old_path, const uni_char *new_path, OpFileFolder folder)
  2096. {
  2097. OpFile old_file;
  2098. OpFile new_file;
  2099. RETURN_IF_ERROR(old_file.Construct(old_path, folder));
  2100. RETURN_IF_ERROR(new_file.Construct(new_path, folder));
  2101. return new_file.SafeReplace(&old_file);
  2102. }
  2103. OP_STATUS BlockStorage::RenameStorage(const uni_char *old_path, const uni_char *new_path, OpFileFolder folder)
  2104. {
  2105. OpString old_journal_path;
  2106. OpString new_journal_path;
  2107. RETURN_IF_ERROR(old_journal_path.Set(old_path));
  2108. RETURN_IF_ERROR(old_journal_path.Append(INVALID_JOURNAL_SUFFIX));
  2109. RETURN_IF_ERROR(new_journal_path.Set(new_path));
  2110. RETURN_IF_ERROR(new_journal_path.Append(INVALID_JOURNAL_SUFFIX));
  2111. if (FileExists(old_journal_path.CStr(), folder) == OpBoolean::IS_TRUE)
  2112. RETURN_IF_ERROR(RenameFile(old_journal_path.CStr(), new_journal_path.CStr()));
  2113. RETURN_IF_ERROR(old_journal_path.Set(old_path));
  2114. RETURN_IF_ERROR(old_journal_path.Append(TRANSACTION_NAME_SUFFIX));
  2115. RETURN_IF_ERROR(new_journal_path.Set(new_path));
  2116. RETURN_IF_ERROR(new_journal_path.Append(TRANSACTION_NAME_SUFFIX));
  2117. if (FileExists(old_journal_path.CStr(), folder) == OpBoolean::IS_TRUE)
  2118. RETURN_IF_ERROR(RenameFile(old_journal_path.CStr(), new_journal_path.CStr()));
  2119. return RenameFile(old_path, new_path, folder);
  2120. }
  2121. OP_STATUS BlockStorage::CreateAssociatedFile(const uni_char *suffix)
  2122. {
  2123. OpLowLevelFile *f = NULL;
  2124. OP_STATUS status;
  2125. RETURN_IF_ERROR(OpenAssociatedFile(&f, OpenReadWrite, suffix));
  2126. if (OpStatus::IsError(status = f->SafeClose()))
  2127. OpStatus::Ignore(f->Delete());
  2128. OP_DELETE(f);
  2129. return status;
  2130. }
  2131. OP_BOOLEAN BlockStorage::AssociatedFileExists(const uni_char *suffix)
  2132. {
  2133. RETURN_IF_ERROR(BuildAssociatedFileName(m_associated_file_name_buf, suffix));
  2134. return FileExists(m_associated_file_name_buf.CStr());
  2135. }
  2136. OP_BOOLEAN BlockStorage::DeleteAssociatedFile(const uni_char *suffix)
  2137. {
  2138. RETURN_IF_ERROR(BuildAssociatedFileName(m_associated_file_name_buf, suffix));
  2139. return DeleteFile(m_associated_file_name_buf.CStr());
  2140. }
  2141. OP_STATUS BlockStorage::OpenAssociatedFile(OpLowLevelFile **f, OpenMode mode, const uni_char *suffix)
  2142. {
  2143. RETURN_IF_ERROR(BuildAssociatedFileName(m_associated_file_name_buf, suffix));
  2144. return OpenOpLowLevelFile(f, m_associated_file_name_buf.CStr(), mode, OPFILE_ABSOLUTE_FOLDER);
  2145. }
  2146. OP_STATUS BlockStorage::BuildAssociatedFileName(OpString &name, const uni_char *suffix)
  2147. {
  2148. if (!m_file)
  2149. return OpStatus::ERR_NULL_POINTER;
  2150. const uni_char *full_path = m_file->GetFullPath();
  2151. name.Reserve((int)uni_strlen(full_path) + (int)uni_strlen(suffix));
  2152. RETURN_IF_ERROR(name.Set(full_path));
  2153. return name.Append(suffix);
  2154. }
  2155. BOOL BlockStorage::IsStartBlock(OpFileLength pos)
  2156. {
  2157. BOOL start_block;
  2158. OpFileLength dummy_next;
  2159. if (m_file == NULL || !m_start_blocks_supported || !IS_NORMAL_BLOCK(pos))
  2160. return FALSE;
  2161. RETURN_VALUE_IF_ERROR(m_file->SetFilePos(pos), FALSE);
  2162. RETURN_VALUE_IF_ERROR(ReadBlockHeader(m_file, &dummy_next, &start_block), FALSE);
  2163. return start_block;
  2164. }
  2165. OP_STATUS BlockStorage::SetStartBlock(OpFileLength pos)
  2166. {
  2167. OpFileLength next, current;
  2168. if (m_file == NULL)
  2169. return OpStatus::ERR;
  2170. OP_ASSERT(!m_start_blocks_supported);
  2171. OP_ASSERT(IS_NORMAL_BLOCK(pos));
  2172. RETURN_IF_ERROR(m_file->SetFilePos(pos));
  2173. RETURN_IF_ERROR(ReadBlockHeader(m_file, &next, NULL));
  2174. //m_file->SetFilePos(pos);
  2175. //RETURN_IF_ERROR(WriteBlockHeader(m_file, next, TRUE)); (Unnecessary, start blocks are 0)
  2176. while (next != 0)
  2177. {
  2178. RETURN_IF_ERROR(m_file->SetFilePos(next));
  2179. current = next;
  2180. RETURN_IF_ERROR(ReadBlockHeader(m_file, &next, NULL));
  2181. m_start_blocks_supported = TRUE; // Temporary, for WriteBlockHeader
  2182. RETURN_IF_ERROR(m_file->SetFilePos(current));
  2183. RETURN_IF_ERROR(WriteBlockHeader(m_file, next, FALSE));
  2184. m_start_blocks_supported = FALSE;
  2185. }
  2186. return OpStatus::OK;
  2187. }
  2188. OP_STATUS BlockStorage::StartBlocksUpdated()
  2189. {
  2190. OP_STATUS rv = OpStatus::OK;
  2191. if (m_file == NULL)
  2192. return OpStatus::ERR;
  2193. OP_ASSERT(!m_start_blocks_supported);
  2194. // NB! As discussed in Delete(), the following block will be obsolete when using
  2195. // a cached bitfield for checking if a block is deleted in IsStartBlock(). (roarl)
  2196. unsigned char *bitfield;
  2197. RETURN_OOM_IF_NULL(bitfield = OP_NEWA(unsigned char, m_blocksize));
  2198. OpFileLength bitfield_pos = 0, file_length, pos;
  2199. RETURN_IF_ERROR_CLEANUP(m_file->GetFileLength(&file_length));
  2200. for (pos = 0; pos < file_length; pos += m_blocksize) {
  2201. if (IS_BITFIELD_BLOCK(pos))
  2202. {
  2203. bitfield_pos = pos;
  2204. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos));
  2205. RETURN_IF_ERROR_CLEANUP(ReadFully(m_file, bitfield, m_blocksize));
  2206. }
  2207. else if (IS_NORMAL_BLOCK(pos))
  2208. {
  2209. int block_no = (int)((pos - bitfield_pos) / m_blocksize - 1);
  2210. if ((bitfield[block_no >> 3] & (1 << (block_no & 7))) != 0)
  2211. {
  2212. m_start_blocks_supported = TRUE; // Temporary, for WriteBlockHeader
  2213. RETURN_IF_ERROR_CLEANUP(m_file->SetFilePos(pos));
  2214. RETURN_IF_ERROR_CLEANUP(WriteBlockHeader(m_file, 0, FALSE));
  2215. m_start_blocks_supported = FALSE;
  2216. }
  2217. }
  2218. }
  2219. OP_DELETEA(bitfield);
  2220. RETURN_IF_ERROR(m_file->SetFilePos(BLOCK_HDR_SIZE));
  2221. RETURN_IF_ERROR(WriteInt32(m_file, BLOCK_FILE_HEADER)); // Becomes correct according to endianness
  2222. m_start_blocks_supported = true;
  2223. return OpStatus::OK;
  2224. cleanup:
  2225. OP_DELETEA(bitfield);
  2226. return rv;
  2227. }
  2228. #ifdef ESTIMATE_MEMORY_USED_AVAILABLE
  2229. size_t BlockStorage::EstimateMemoryUsed() const
  2230. {
  2231. size_t sum = 0;
  2232. if (m_file)
  2233. sum += sizeof(OpLowLevelFile) + 2*sizeof(size_t);
  2234. if (m_transaction)
  2235. sum += sizeof(OpLowLevelFile) + 2*sizeof(size_t);
  2236. return sum +
  2237. sizeof(m_file) +
  2238. sizeof(m_transaction) +
  2239. sizeof(m_blocksize) +
  2240. sizeof(m_EndianCallback) +
  2241. sizeof(m_callback_arg) +
  2242. sizeof(m_start_blocks_supported) +
  2243. sizeof(m_freeblock) +
  2244. sizeof(m_journal_compressor) +
  2245. sizeof(m_transaction_blocks) +
  2246. sizeof(m_reserved_area) +
  2247. sizeof(m_reserved_size) +
  2248. sizeof(m_reserved_deleted) +
  2249. sizeof(m_next_in_group);
  2250. }
  2251. #endif
  2252. void SearchGroupable::GroupWith(SearchGroupable &group_member)
  2253. {
  2254. GetGroupMember().GroupWith(group_member.GetGroupMember());
  2255. }
  2256. BOOL SearchGroupable::IsFullyCommitted()
  2257. {
  2258. return GetGroupMember().IsFullyCommitted();
  2259. }
  2260. void BlockStorage::GroupWith(BlockStorage &group_member)
  2261. {
  2262. // Ensure that we are not already grouped
  2263. BlockStorage *tmp = this;
  2264. do
  2265. {
  2266. if (tmp == &group_member)
  2267. return;
  2268. tmp = tmp->m_next_in_group;
  2269. }
  2270. while (tmp != this);
  2271. // Widen the loop
  2272. tmp = m_next_in_group;
  2273. m_next_in_group = group_member.m_next_in_group;
  2274. group_member.m_next_in_group = tmp;
  2275. #ifdef _DEBUG
  2276. // Ensure that none of the group members have been opened yet
  2277. tmp = this;
  2278. do
  2279. {
  2280. OP_ASSERT(!tmp->IsOpen());
  2281. tmp = tmp->m_next_in_group;
  2282. }
  2283. while (tmp != this);
  2284. #endif
  2285. }
  2286. void BlockStorage::UnGroup()
  2287. {
  2288. BlockStorage *prev_in_group = this;
  2289. while (prev_in_group->m_next_in_group != this)
  2290. prev_in_group = prev_in_group->m_next_in_group;
  2291. // Remove this from loop
  2292. prev_in_group->m_next_in_group = m_next_in_group;
  2293. m_next_in_group = this;
  2294. }
  2295. BOOL BlockStorage::IsFullyCommitted()
  2296. {
  2297. BlockStorage *tmp = this;
  2298. do
  2299. {
  2300. if (tmp->InTransaction() || tmp->WaitingForGroupCommit())
  2301. return FALSE;
  2302. tmp = tmp->m_next_in_group;
  2303. }
  2304. while (tmp != this);
  2305. return TRUE;
  2306. }
  2307. BlockStorage *BlockStorage::GetFirstInGroup()
  2308. {
  2309. BlockStorage *group_member = this;
  2310. do
  2311. {
  2312. if (group_member->m_first_in_group)
  2313. return group_member;
  2314. group_member = group_member->m_next_in_group;
  2315. }
  2316. while (group_member != this);
  2317. // Nobody called GetFirstInGroup yet, this must be the first
  2318. m_first_in_group = TRUE;
  2319. return this;
  2320. }
  2321. #undef OLD_JOURNAL_FILE_HEADER
  2322. #undef OLD_JOURNAL_FILE_HEADER_I
  2323. #undef BLOCK_FILE_HEADER_0201
  2324. #undef BLOCK_FILE_HEADER_0201_I
  2325. #undef BLOCK_FILE_HEADER_0202
  2326. #undef BLOCK_FILE_HEADER_0202_I
  2327. #undef BLOCK_FILE_HEADER
  2328. #undef BLOCK_FILE_HEADER_I
  2329. #undef FILE_HDR_SIZE
  2330. #undef BLOCK_HDR_SIZE
  2331. #undef JOURNAL_HDR_SIZE
  2332. #undef TRANSACTION_NAME_SUFFIX
  2333. #undef INVALID_JOURNAL_SUFFIX
  2334. #undef RETURN_IF_ERROR_CLEANUP
  2335. #undef DISTANCE_BETWEEN_BITFIELDS
  2336. #undef DISTANCE_BEHIND_BITFIELD
  2337. #undef BITFIELD_POS
  2338. #undef IS_BITFIELD_BLOCK
  2339. #undef AT_BLOCK_BOUNDARY
  2340. #undef IS_NORMAL_BLOCK
  2341. #undef IS_START_BLOCK
  2342. #undef IS_NOT_START_BLOCK
  2343. #undef SWAP_UINT32
  2344. #undef ANY_INT64
  2345. #undef BS_RESERVE_BLOCKS
  2346. #endif // SEARCH_ENGINE