00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <errno.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024
00025 #include "mfile.h"
00026 #include "tools.h"
00027
00028
00029
00030
00031
00032 ht_mod_page::ht_mod_page(UINT s)
00033 {
00034 size = s;
00035 data = (byte*)malloc(size);
00036 }
00037
00038 ht_mod_page::~ht_mod_page()
00039 {
00040 free(data);
00041 }
00042
00043 UINT ht_mod_page::read(PAGEOFS pofs, byte *buf, UINT len)
00044 {
00045 UINT s = len;
00046 if (pofs+s > size) s = size-pofs;
00047 memmove(buf, data+pofs, s);
00048 return s;
00049 }
00050
00051 UINT ht_mod_page::write(PAGEOFS pofs, const byte *buf, UINT len)
00052 {
00053 UINT s = len;
00054 if (pofs+s > size) s = size-pofs;
00055 memmove(data+pofs, buf, s);
00056 return s;
00057 }
00058
00059
00060
00061
00062
00063 int compare_keys_file_delinear(Object *key_a, Object *key_b)
00064 {
00065 FILEOFS a = (FILEOFS)delinearize((dword)((ht_data_uint*)key_a)->value);
00066 FILEOFS b = (FILEOFS)delinearize((dword)((ht_data_uint*)key_b)->value);
00067 return a-b;
00068 }
00069
00070 void ht_streamfile_modifier::init(ht_streamfile *s, int own_s, UINT pgran)
00071 {
00072 ht_layer_streamfile::init(s, own_s);
00073
00074 page_granularity = pgran;
00075 page_mask = ~(page_granularity-1);
00076
00077 offset = 0;
00078 active = get_access_mode() & FAM_WRITE;
00079
00080 modified = false;
00081 mod_pages_create();
00082 }
00083
00084 void ht_streamfile_modifier::done()
00085 {
00086 mod_pages_destroy();
00087
00088 ht_layer_streamfile::done();
00089 }
00090
00091 bool ht_streamfile_modifier::isdirty(FILEOFS offset, UINT range)
00092 {
00093 if (range & IS_DIRTY_SINGLEBIT) {
00094 return isdirtybit(offset, range & 7);
00095 } else {
00096 while (range--) if (isdirtybyte(offset++)) return true;
00097 }
00098 return false;
00099 }
00100
00101 bool ht_streamfile_modifier::isdirtybit(FILEOFS offset, UINT bit)
00102 {
00103 ht_mod_page *m = mod_page_find(offset);
00104 if (m) {
00105 byte b1, b2;
00106 ht_layer_streamfile::seek(offset);
00107 if (!ht_layer_streamfile::read(&b1, 1)) return true;
00108 if (!m->read(offset % page_granularity, &b2, 1)) return true;
00109 return (((b1 >> bit) &1) != ((b2 >> bit) &1));
00110 }
00111 return false;
00112 }
00113
00114 bool ht_streamfile_modifier::isdirtybyte(FILEOFS offset)
00115 {
00116 ht_mod_page *m = mod_page_find(offset);
00117 if (m) {
00118 byte b1, b2;
00119 ht_layer_streamfile::seek(offset);
00120 if (!ht_layer_streamfile::read(&b1, 1)) return true;
00121 if (!m->read(offset % page_granularity, &b2, 1)) return true;
00122 return (b1 != b2);
00123 }
00124 return false;
00125 }
00126
00127 void ht_streamfile_modifier::cleardirtybyte(FILEOFS offset)
00128 {
00129 ht_mod_page *m = mod_page_find(offset);
00130 if (m) {
00131 byte b1;
00132 ht_layer_streamfile::seek(offset);
00133 if (ht_layer_streamfile::read(&b1, 1)) {
00134 m->write(offset % page_granularity, &b1, 1);
00135 }
00136 }
00137 }
00138
00139 void ht_streamfile_modifier::mod_pages_create()
00140 {
00141 #if 1
00142 ht_dtree *m=new ht_dtree();
00143 m->init(compare_keys_file_delinear, 250, 250);
00144 #else
00145 ht_stree *m=new ht_stree();
00146 m->init(compare_keys_file_delinear);
00147 #endif
00148 mod_pages=m;
00149 size = ht_layer_streamfile::get_size();
00150 }
00151
00152 void ht_streamfile_modifier::mod_pages_destroy()
00153 {
00154 mod_pages->destroy();
00155 delete mod_pages;
00156 modified = false;
00157 }
00158
00159 void ht_streamfile_modifier::mod_pages_flush()
00160 {
00161 ht_data_uint *key=NULL;
00162 Object *value;
00163
00164 while ((key=(ht_data_uint*)mod_pages->enum_next(&value, key))) {
00165 mod_page_flush(key->value);
00166 }
00167
00168 UINT lsize = ht_layer_streamfile::get_size();
00169 if (size > lsize) {
00170 ht_layer_streamfile::extend(size);
00171 } else if (size < lsize) {
00172 ht_layer_streamfile::truncate(size);
00173 }
00174
00175 modified = false;
00176 }
00177
00178 void ht_streamfile_modifier::mod_pages_invd()
00179 {
00180 mod_pages_destroy();
00181 mod_pages_create();
00182 }
00183
00184 ht_mod_page *ht_streamfile_modifier::mod_page_create(FILEOFS offset)
00185 {
00186 offset &= page_mask;
00187 if (offset > size) return NULL;
00188
00189 UINT s = size - offset;
00190 if (s > page_granularity) s = page_granularity;
00191
00192 ht_mod_page *m = new ht_mod_page(page_granularity);
00193 UINT lsize = ht_layer_streamfile::get_size();
00194 UINT rsize = s;
00195 if (offset > lsize) rsize = 0; else
00196 if (rsize > lsize - offset) rsize = lsize - offset;
00197 ht_layer_streamfile::seek(offset);
00198 ht_layer_streamfile::read(m->data, rsize);
00199 memset(m->data+rsize, 0, page_granularity-rsize);
00200 mod_pages->insert(new ht_data_uint(offset), m);
00201 return m;
00202 }
00203
00204 void ht_streamfile_modifier::mod_page_destroy(FILEOFS offset)
00205 {
00206 ht_data_uint o(offset);
00207 mod_pages->del(&o);
00208 }
00209
00210 ht_mod_page *ht_streamfile_modifier::mod_page_find(FILEOFS offset)
00211 {
00212 ht_data_uint o(offset & page_mask);
00213 return (ht_mod_page*)mod_pages->get(&o);
00214 }
00215
00216 void ht_streamfile_modifier::mod_page_flush(FILEOFS offset)
00217 {
00218 ht_mod_page *m = mod_page_find(offset);
00219 UINT s = m->size;
00220 if (offset+s > size) s = size-offset;
00221 ht_layer_streamfile::seek(offset);
00222 ht_layer_streamfile::write(m->data, s);
00223 }
00224
00225 int ht_streamfile_modifier::extend(UINT newsize)
00226 {
00227
00228 if (!active) return EIO;
00229 UINT osize = size;
00230
00231 if (size != newsize) modified = true;
00232 size = newsize;
00233 for (FILEOFS o = osize & page_mask; o < size; o += page_granularity) {
00234 if (!mod_page_find(o)) mod_page_create(o);
00235 }
00236
00237 return 0;
00238
00239 }
00240
00241 UINT ht_streamfile_modifier::get_size()
00242 {
00243 if (!active) return ht_layer_streamfile::get_size();
00244 return size;
00245 }
00246
00247 UINT ht_streamfile_modifier::read(void *buf, UINT s)
00248 {
00249 if (!active) return ht_layer_streamfile::read(buf, s);
00250 UINT c = 0;
00251 byte *b = (byte*)buf;
00252 FILEOFS o = tell();
00253 #if 0
00254 while (s--) {
00255 if (o+c >= size) break;
00256 if (!readbyte(o+c, &b[c])) {
00257 set_error(EIO);
00258 break;
00259 }
00260 c++;
00261 }
00262 #else
00263 if (s >= 8) {
00264 ht_mod_page *m;
00265 while (s) {
00266 m = mod_page_find(o);
00267 UINT lc = page_granularity - (o & (~page_mask));
00268 if (lc > s) lc = s;
00269 if (o + lc > size) lc = size - o;
00270 if (!lc) break;
00271
00272 UINT k;
00273 if (m) {
00274 k = m->read(o & (~page_mask), b, lc);
00275 } else {
00276 ht_layer_streamfile::seek(o);
00277 k = ht_layer_streamfile::read(b, lc);
00278 }
00279 if (!k) break;
00280 s -= k;
00281 o += k;
00282 c += k;
00283 b += k;
00284 }
00285 } else {
00286 while (s--) {
00287 if (o+c >= size) break;
00288 if (!readbyte(o+c, &b[c])) {
00289 set_error(EIO);
00290 break;
00291 }
00292 c++;
00293 }
00294 }
00295 #endif
00296 offset+=c;
00297 return c;
00298 }
00299
00300 bool ht_streamfile_modifier::readbyte(FILEOFS offset, byte *b)
00301 {
00302 ht_mod_page *m = mod_page_find(offset);
00303 if (m) {
00304 return (m->read(offset % page_granularity, b, 1)==1);
00305 }
00306 ht_layer_streamfile::seek(offset);
00307 return (ht_layer_streamfile::read(b, 1)==1);
00308 }
00309
00310 int ht_streamfile_modifier::seek(FILEOFS o)
00311 {
00312 if (!active) return ht_layer_streamfile::seek(o);
00313 offset = o;
00314 if (o >= size) return EINVAL;
00315 return 0;
00316 }
00317
00318 bool ht_streamfile_modifier::set_access_mode(UINT access_mode)
00319 {
00320 bool b=ht_layer_streamfile::set_access_mode(access_mode);
00321 if (get_access_mode() & FAM_WRITE) {
00322 active = true;
00323 } else {
00324 if (active) mod_pages_invd();
00325 active = false;
00326 }
00327 return b;
00328 }
00329
00330 FILEOFS ht_streamfile_modifier::tell()
00331 {
00332 if (!active) return ht_layer_streamfile::tell();
00333 return offset;
00334 }
00335
00336 int ht_streamfile_modifier::truncate(UINT newsize)
00337 {
00338
00339 if (!active) return EIO;
00340 for (FILEOFS o = (newsize+page_granularity-1) & page_mask; o < size;
00341 o += page_granularity) {
00342 mod_page_destroy(o);
00343 }
00344 if (size != newsize) modified = true;
00345 size = newsize;
00346
00347 return 0;
00348 }
00349
00350 int ht_streamfile_modifier::vcntl(UINT cmd, va_list vargs)
00351 {
00352 if (active) switch (cmd) {
00353 case FCNTL_MODS_INVD:
00354 mod_pages_invd();
00355 return 0;
00356 case FCNTL_MODS_FLUSH:
00357 mod_pages_flush();
00358 return 0;
00359 case FCNTL_MODS_CLEAR_DIRTY_RANGE: {
00360 FILEOFS o=va_arg(vargs, FILEOFS);
00361 UINT s=va_arg(vargs, UINT);
00362 UINT i=0;
00363 while (s--) {
00364 cleardirtybyte(o+i);
00365 i++;
00366 }
00367 return 0;
00368 }
00369 case FCNTL_MODS_IS_DIRTY: {
00370 FILEOFS o=va_arg(vargs, FILEOFS);
00371 UINT s=va_arg(vargs, UINT);
00372 bool *b=va_arg(vargs, bool*);
00373 if ((o==0) && (s==size)) {
00374 *b = modified;
00375 } else {
00376 *b = isdirty(o, s);
00377 }
00378 return 0;
00379 }
00380 }
00381 return ht_layer_streamfile::vcntl(cmd, vargs);
00382 }
00383
00384 UINT ht_streamfile_modifier::write(const void *buf, UINT s)
00385 {
00386 if (!active) return ht_layer_streamfile::write(buf, s);
00387 FILEOFS o = tell();
00388 byte *b = (byte*)buf;
00389 UINT c = 0;
00390
00391 #if 0
00392 while (s--) {
00393 if (o+c >= size) break;
00394 if (!writebyte(o+c, b[c])) {
00395 set_error(EIO);
00396 break;
00397 }
00398 c++;
00399 }
00400 #else
00401 if (s >= 8) {
00402 ht_mod_page *m;
00403 while (s) {
00404 m = mod_page_find(o);
00405 if (!m) m = mod_page_create(o);
00406 UINT lc = page_granularity - (o & (~page_mask));
00407 if (lc > s) lc = s;
00408
00409 UINT k;
00410
00411 modified = true;
00412 k = m->write(o & (~page_mask), b, lc);
00413 if (!k) break;
00414 s -= k;
00415 o += k;
00416 c += k;
00417 b += k;
00418 }
00419 } else {
00420 while (s--) {
00421 if (o+c >= size) break;
00422 if (!writebyte(o+c, b[c])) {
00423 set_error(EIO);
00424 break;
00425 }
00426 c++;
00427 }
00428 }
00429 #endif
00430 offset+=c;
00431 return c;
00432 }
00433
00434 bool ht_streamfile_modifier::writebyte(FILEOFS offset, byte b)
00435 {
00436 ht_mod_page *m = mod_page_find(offset);
00437 if (!m) m = mod_page_create(offset);
00438 byte t = b;
00439 m->read(offset % page_granularity, &t, 1);
00440 modified |= (t!=b);
00441 return (m->write(offset % page_granularity, &b, 1)==1);
00442 }
00443