Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

mfile.cc

Go to the documentation of this file.
00001 /*
00002  *      HT Editor
00003  *      mfile.cc
00004  *
00005  *      Copyright (C) 1999-2002 Stefan Weyergraf (stefan@weyergraf.de)
00006  *
00007  *      This program is free software; you can redistribute it and/or modify
00008  *      it under the terms of the GNU General Public License version 2 as
00009  *      published by the Free Software Foundation.
00010  *
00011  *      This program is distributed in the hope that it will be useful,
00012  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *      GNU General Public License for more details.
00015  *
00016  *      You should have received a copy of the GNU General Public License
00017  *      along with this program; if not, write to the Free Software
00018  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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  *      CLASS ht_mod_page
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  *      CLASS ht_streamfile_modifier
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         // must be opened writable to extend
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 //      return ht_layer_streamfile::extend(newsize);
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         // must be opened writable to truncate
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                         // FIXME: not the right thing
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 

Generated on Fri May 7 21:15:41 2004 by doxygen 1.3.5