📄 mfile.cc
字号:
memcpy(b->buf, m->buf+d, b->size); m->size = d; m->buf = (byte*)realloc(m->buf, d); mods += b; // create new MFAs between 'a' and 'b' FileOfs start = t; while (ssize != 0) { FileOfs k = MAX_MFA_SIZE; if (k > ssize) k = ssize; mods += new ModifiedFileArea(start, k); ssize -= k; start += k; } } } else { // no, append. FileOfs start = t; while (ssize != 0) { FileOfs k = MAX_MFA_SIZE; if (k > ssize) k = ssize; mods += new ModifiedFileArea(start, k); ssize -= k; start += k; } } // (2) write data const byte *b = (const byte*)buf; FileOfs o = t; h = findArea(o); while (size && (h != invObjHandle)) { FileArea *a = (FileArea*)mods.get(h); FileOfs s = o - a->start; FileOfs z = a->size - s; if (z > size) z = size; if (z > a->size) z = a->size;// ht_printf("%qx, now write %qx\n", a->start, z); write1(a, s, b, z); o += z; size -= z; b += z; h = mods.findNext(h); } newsize += o-t; seek(o); mcount++;}void FileModificator::makeAreaModified(ObjHandle h, FileOfs rstart, FileOfs size){ FileArea *a = (FileArea*)mods.get(h); if (a->getObjectID() == OBJID_CFA) { // not marked modified, do something CopiedFileArea *c = (CopiedFileArea*)a; FileOfs csrc_start = c->src_start; FileOfs cstart = c->start; FileOfs csize = c->size; bool have_head_gap = rstart != 0; bool have_tail_gap = csize > rstart+size; ModifiedFileArea *prev_m = (ModifiedFileArea*)mods.get(mods.findPrev(h));// ASSERT(!prev_m || (prev_m->getObjectID() == OBJID_MFA)); if (prev_m && (prev_m->getObjectID() != OBJID_MFA)) prev_m = NULL; ModifiedFileArea *next_m = (ModifiedFileArea*)mods.get(mods.findNext(h)); if (next_m && (next_m->getObjectID() != OBJID_MFA)) next_m = NULL;// ASSERT(!next_m || (next_m->getObjectID() == OBJID_MFA)); // "min condition" // =============== // trick for FA packing: we simply make modified areas bigger // than they would have to be. (either at least MIN_COND_MFA_SIZE // big or adjacent/mergable with another MFA) bool min_condition = (size < MIN_COND_MFA_SIZE) && (!prev_m || have_head_gap) && (!next_m || have_tail_gap); FileOfs min_addsize; FileOfs min_ofs; FileOfs min_src_ofs; if (min_condition) { // if the MFA we will create would be too small, make it bigger // (compare gap sizes, then try to reach boundary to // reduce number of FAs) if (rstart < csize-rstart-size) { // head gap is smaller than tail gap FileOfs z = rstart; if (z+size > MIN_COND_MFA_SIZE) z = MIN_COND_MFA_SIZE-size; min_addsize = z; min_ofs = cstart+rstart-z; min_src_ofs = csrc_start+rstart-z; rstart -= z; } else { // tail gap is smaller than head gap FileOfs z = csize-rstart-size; if (z+size > MIN_COND_MFA_SIZE) z = MIN_COND_MFA_SIZE-size; min_addsize = z; min_ofs = cstart+rstart+size; min_src_ofs = csrc_start+rstart+size; } size += min_addsize; have_head_gap = rstart != 0; have_tail_gap = csize > rstart+size; } if (have_head_gap) { c->size = rstart; cstart += rstart; csrc_start += rstart; csize -= rstart; } else { mods -= h; } if (next_m && !have_tail_gap) { // merge with next MFA (successor) FileOfs nnsize = next_m->size + size; if (nnsize > MAX_MFA_SIZE) nnsize = MAX_MFA_SIZE; mods.removeObj(next_m); FileOfs rnnsize = nnsize - next_m->size; next_m->buf = (byte*)realloc(next_m->buf, nnsize); next_m->start -= rnnsize; memmove(next_m->buf+rnnsize, next_m->buf, next_m->size); next_m->size = nnsize; mods += next_m; csize -= rnnsize; size -= rnnsize; } if (prev_m && !have_head_gap) { // merge with previous MFA (predecessor) FileOfs pnsize = prev_m->size + size; if (pnsize > MAX_MFA_SIZE) pnsize = MAX_MFA_SIZE; FileOfs rpnsize = pnsize - prev_m->size; prev_m->size = pnsize; prev_m->buf = (byte*)realloc(prev_m->buf, pnsize); csrc_start += rpnsize; cstart += rpnsize; csize -= rpnsize; size -= rpnsize; } while (size != 0) { FileOfs k = MAX_MFA_SIZE; if (k > size) k = size; mods += new ModifiedFileArea(cstart, k); size -= k; csize -= k; cstart += k; csrc_start += k; } if (have_tail_gap) { mods += new CopiedFileArea(cstart, csize, csrc_start); } if (min_condition) { byte *buf = ht_malloc(min_addsize); mFile->seek(min_src_ofs); mFile->readx(buf, min_addsize); ObjHandle ha = findArea(min_ofs); while (min_addsize != 0) { FileArea *a = (FileArea*)mods.get(ha); assert(dynamic_cast<ModifiedFileArea*>(a)); FileOfs k = min_addsize; if (k > a->size- (min_ofs-a->start)) k = a->size- (min_ofs-a->start); write1(a, min_ofs - a->start, buf, k); min_addsize -= k; min_ofs += k; ha = mods.findNext(ha); } free(buf); } }}void FileModificator::read1(FileArea *a, FileOfs rstart, byte *buf, uint count){ CopiedFileArea *c; ModifiedFileArea *m; if ((m = dynamic_cast<ModifiedFileArea*>(a))) { memcpy(buf, m->buf + rstart, count); } else if ((c = dynamic_cast<CopiedFileArea*>(a))) { mFile->seek(c->src_start+rstart); mFile->read(buf, count); } else assert(0);}uint FileModificator::read(void *buf, uint size){ if (!(getAccessMode() & IOAM_READ)) throw IOException(EACCES); FileOfs t = tell(); if (t == 0x00000000ULL) { int a = 1; } FileOfs o = t; ObjHandle h = findArea(o); byte *b = (byte*)buf; while (size && h != invObjHandle) { FileArea *a = (FileArea*)mods.get(h); FileOfs s = o - a->start; FileOfs z = a->size - s; if (z > size) z = size; h = mods.findNext(h); read1(a, s, b, z); o += z; size -= z; b += z; } seek(o); return o - t;}void FileModificator::seek(FileOfs offset){ if (offset > newsize) throw IOException(EINVAL); pos = offset;}FileOfs FileModificator::tell() const{ return pos;}void FileModificator::truncate(FileOfs Newsize){ if (Newsize == newsize) return; if (Newsize > newsize) throw IOException(EINVAL); if (!(getAccessMode() & IOAM_WRITE)) throw IOException(EACCES); seek(0); ObjHandle h = findArea(Newsize); FileArea *a = (FileArea*)mods.get(h); if (a->start < Newsize) { if (a->getObjectID() == OBJID_CFA) { CopiedFileArea *c = (CopiedFileArea*)a; c->size = Newsize - a->start; } else { ModifiedFileArea *m = (ModifiedFileArea*)a; m->size = Newsize - a->start; m->buf = (byte*)realloc(m->buf, m->size); } h = mods.findNext(h); } while (h != invObjHandle) { ObjHandle hnext = mods.findNext(h); FileArea *a = (FileArea*)mods.get(hnext); mods -= h; if (!a) break; h = findArea(a->start); } newsize = Newsize; mcount++;}void FileModificator::flushMods(){ // make sure we can read and write int e; IOAccessMode old_am = mFile->getAccessMode(); e = mFile->setAccessMode(IOAM_READ | IOAM_WRITE); if (e) throw IOException(e); // start work if (newsize > mFile->getSize()) mFile->extend(newsize); // store CFAs with start > src_start in descending order foreachbwd(FileArea, fa, mods, if (fa->getObjectID() == OBJID_CFA) { CopiedFileArea *cfa = (CopiedFileArea*)fa; if (cfa->start > cfa->src_start) { mFile->move(cfa->src_start, cfa->start, cfa->size); } } ); // store CFAs with start < src_start in ascending order foreach(FileArea, fa, mods, if (fa->getObjectID() == OBJID_CFA) { CopiedFileArea *cfa = (CopiedFileArea*)fa; if (cfa->start < cfa->src_start) { mFile->move(cfa->src_start, cfa->start, cfa->size); } } ); // store MFAs foreach(FileArea, fa, mods, if (fa->getObjectID() == OBJID_MFA) { ModifiedFileArea *mfa = (ModifiedFileArea*)fa; mFile->seek(mfa->start); mFile->writex(mfa->buf, mfa->size); } ); // if (newsize < mFile->getSize()) mFile->truncate(newsize); // restore old access mode e = mFile->setAccessMode(old_am); if (e) throw IOException(e); // inv_mcount = mcount; invalidateMods();}void FileModificator::invalidateMods(){ mods.delAll(); newsize = mFile->getSize(); if (newsize != 0) mods += new CopiedFileArea(0, newsize, 0); pos = 0; mcount = inv_mcount;}bool FileModificator::isModified() const{ if (newsize != mFile->getSize()) return true; foreach(FileArea, fa, mods, CopiedFileArea *cfa = dynamic_cast<CopiedFileArea*>(fa); if (!cfa || (cfa->start != cfa->src_start)) return true; ); return false;}bool FileModificator::isModifiedByte(FileOfs o){ ObjHandle h = findArea(o); FileArea *fa = (FileArea*)mods.get(h); if (!fa) return true; if (fa->getObjectID() == OBJID_MFA) { ModifiedFileArea *mfa = (ModifiedFileArea*)fa; int pg_ofs = o - fa->start; byte b; mFile->seek(o); mFile->readx(&b, 1); return mfa->buf[pg_ofs] != b; } else if (fa->getObjectID() == OBJID_CFA) { CopiedFileArea *cfa = (CopiedFileArea*)fa; if (cfa->src_start == cfa->start) return false; int pg_ofs = o - fa->start; byte b1, b2; mFile->seek(o); mFile->readx(&b1, 1); mFile->seek(cfa->src_start + pg_ofs); mFile->readx(&b2, 1); return (b1 != b2); } return false;}int FileModificator::vcntl(uint cmd, va_list vargs){ switch (cmd) { case FCNTL_MODS_INVD: invalidateMods(); return 0; case FCNTL_MODS_FLUSH: flushMods(); return 0; case FCNTL_MODS_CLEAR_DIRTY_RANGE: {/* // BEFORE-IMPLEMENT: decl changed ! FileOfs o = va_arg(vargs, FileOfs); uint s = va_arg(vargs, uint); uint i = 0; while (s--) { cleardirtybyte(o+i); i++; }*/ return 0; } case FCNTL_MODS_IS_DIRTY: { // const FileOfs offset, const FileOfs range, bool &isdirty FileOfs o = va_arg(vargs, FileOfs); FileOfs s = va_arg(vargs, FileOfs); bool &b = (bool&)*va_arg(vargs, bool*); if (o == 0 && s == newsize) { b = isModified(); } else if (s <= 16) { try { bool bb = false; while (s--) { bb |= isModifiedByte(o++); } b = bb; } catch (const IOException &x) { return EIO; } } else { return ENOSYS; } return 0; } case FCNTL_GET_MOD_COUNT: { // int &mcount int *mc = va_arg(vargs, int *); *mc = mcount; return 0; } } return mFile->vcntl(cmd, vargs);}void FileModificator::write1(FileArea *a, FileOfs rstart, const byte *buf, uint count){ assert(a->getObjectID() == OBJID_MFA);// ObjectID id = a->getObjectID(); ModifiedFileArea *m = (ModifiedFileArea*)a; memcpy(m->buf+rstart, buf, count);}uint FileModificator::write(const void *buf, uint size){ if (!(getAccessMode() & IOAM_WRITE)) throw IOException(EACCES); // (1) make areas modified FileOfs t = tell(); FileOfs o = t; uint osize = size; while (size) { ObjHandle h = findArea(o); if (h == invObjHandle) break; FileArea *a = (FileArea*)mods.get(h); FileOfs s = o - a->start; FileOfs z = a->size - s; if (z > size) z = size; makeAreaModified(h, s, z); o += z; size -= z; } // (2) write data const byte *b = (const byte*)buf; o = t; size = osize; ObjHandle h = findArea(o); while (size && (h != invObjHandle)) { FileArea *a = (FileArea*)mods.get(h); FileOfs s = o - a->start; FileOfs z = a->size - s; if (z > size) z = size; if (z > a->size) z = a->size; write1(a, s, b, z); o += z; size -= z; b += z; h = mods.findNext(h); } seek(o); mcount++; return o - t;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -