static void scanSource(Fsck *chk, char *name, Source *r) { u32int a, nb, o; Block *b; Entry e; if(!chk->useventi && globalToLocal(r->score)==NilBlock) return; if(!sourceGetEntry(r, &e)){ error(chk, "could not get entry for %s", name); return; } a = globalToLocal(e.score); if(!chk->useventi && a==NilBlock) return; if(getBit(chk->smap, a)) return; setBit(chk->smap, a); nb = (sourceGetSize(r) + r->dsize-1) / r->dsize; for(o = 0; o < nb; o++){ b = sourceBlock(r, o, OReadOnly); if(b == nil){ error(chk, "could not read block in data file %s", name); continue; } if(b->addr != NilBlock && getBit(chk->errmap, b->addr)){ warn(chk, "previously reported error in block %ux is in file %s", b->addr, name); } blockPut(b); } }
void ScrollBar::handleScrollTouch(ds::ui::Sprite* bs, const ds::ui::TouchInfo& ti){ if(ti.mFingerIndex == 0){ ci::Vec3f localPos = globalToLocal(ti.mCurrentGlobalPoint); float destPercent; if(mVertical){ // This may not be right. Feel free to fix, but be sure you get it right and check multiple instances if(getPerspective()){ localPos.y -= getHeight()/2.0f; } destPercent = localPos.y / getHeight(); } else { destPercent = localPos.x / getWidth(); } if(destPercent < 0.0f) destPercent = 0.0f; if(destPercent > 1.0f) destPercent = 1.0f; if(mScrollMoveCallback){ mScrollMoveCallback(destPercent); } } }
bool Slider::touchMoveHandler(ofTouchEventArgs &touch){ if (touch.id == currentTouchId){ setCursorPosition(globalToLocal(touch.x, touch.y)); return true; } return false; }
bool Slider::touchDownHandler(ofTouchEventArgs &touch){ if (cursorPosition.distance(globalToLocal(touch.x, touch.y)) < cursorRadius * radiusTouchFactor){ currentTouchId = touch.id; return true; } return false; }
void TreeInspector::highlightSprite( const ds::ui::Sprite* sprite ) { auto showHighlight = [&]( const ds::ui::Sprite* s ) { if (!mHighlighter) { mHighlighter = new ds::ui::Sprite( mEngine ); mHighlighter->setTransparent( false ); mHighlighter->setColorA( ci::ColorA::hexA( 0xAA6fa8dc ) ); addChildPtr( mHighlighter ); auto crosshairColor = ci::Color::hex( (0xf6b26b) ); auto hCrosshair = new ds::ui::Sprite( mEngine, 40.0f, 3.0f ); hCrosshair->setTransparent( false ); hCrosshair->setColor( crosshairColor ); mHighlighter->addChildPtr( hCrosshair ); auto vCrosshair = new ds::ui::Sprite( mEngine, 3.0f, 40.0f ); vCrosshair->setTransparent( false ); vCrosshair->setColor( crosshairColor ); mHighlighter->addChildPtr( vCrosshair ); } mHighlighter->show(); mHighlighter->setSize( s->getWidth(), s->getHeight() ); auto pos = s->getGlobalPosition(); mHighlighter->setPosition( globalToLocal( pos ) ); }; if (sprite) { showHighlight(sprite); } else if (mHighlighter) { mHighlighter->hide(); } }
void entryPack(Entry *e, uchar *p, int index) { ulong t32; int flags; p += index * VtEntrySize; U32PUT(p, e->gen); U16PUT(p+4, e->psize); U16PUT(p+6, e->dsize); flags = e->flags | ((e->depth << VtEntryDepthShift) & VtEntryDepthMask); U8PUT(p+8, flags); memset(p+9, 0, 5); U48PUT(p+14, e->size, t32); if(flags & VtEntryLocal){ if(globalToLocal(e->score) == NilBlock) abort(); memset(p+20, 0, 7); U8PUT(p+27, e->archive); U32PUT(p+28, e->snap); U32PUT(p+32, e->tag); memmove(p+36, e->score+16, 4); }else memmove(p+20, e->score, VtScoreSize); }
void LocalMapLayer::updateRefereceRobotFrame(GeoObjectID id, MapAbstraction::MapRobotObjectPtr robot) { MapAbstraction::MapObjectPtr frozen(robot->Clone()); QPointF local; globalToLocal(MapLibraryHelpers::transformCoords(robot->coords()), local); frozen->setCoords(MapAbstraction::GeoCoords(local.x(), local.y())); mRobotReferenceFrames.insert(id, frozen.staticCast<MapAbstraction::MapRobotObject>()); }
static int sourceKill(Source *r, int doremove) { Entry e; Block *b; uint32_t addr; uint32_t tag; int type; assert(sourceIsLocked(r)); b = sourceLoad(r, &e); if(b == nil) return 0; assert(b->l.epoch == r->fs->ehi); if(doremove==0 && e.size == 0) { /* already truncated */ blockPut(b); return 1; } /* remember info on link we are removing */ addr = globalToLocal(e.score); type = entryType(&e); tag = e.tag; if(doremove) { if(e.gen != ~0) e.gen++; e.dsize = 0; e.psize = 0; e.flags = 0; } else { e.flags &= ~VtEntryLocal; } e.depth = 0; e.size = 0; e.tag = 0; memmove(e.score, vtZeroScore, VtScoreSize); entryPack(&e, b->data, r->offset % r->epb); blockDirty(b); if(addr != NilBlock) blockRemoveLink(b, addr, type, tag, 1); blockPut(b); if(doremove) { sourceUnlock(r); sourceClose(r); } return 1; }
bool Aspring::handleEvent(Aevent* evt) { if(evt->Type == MOUSE_PRESS_EVENT) { Vec3f localPoint = globalToLocal(evt->mousePos); if( pointInside( localPoint )){ if(COLLIDER->mEditor != NULL) COLLIDER->mEditor->registerSpring(this); return true; } } return false; }
static void checkEpoch(Fsck *chk, u32int epoch) { u32int a; Block *b; Entry e; Label l; chk->print("checking epoch %ud...\n", epoch); for(a=0; a<chk->nblocks; a++){ if(!readLabel(chk->cache, &l, (a+chk->hint)%chk->nblocks)){ error(chk, "could not read label for addr 0x%.8#ux", a); continue; } if(l.tag == RootTag && l.epoch == epoch) break; } if(a == chk->nblocks){ chk->print("could not find root block for epoch %ud", epoch); return; } a = (a+chk->hint)%chk->nblocks; b = cacheLocalData(chk->cache, a, BtDir, RootTag, OReadOnly, 0); if(b == nil){ error(chk, "could not read root block 0x%.8#ux: %R", a); return; } /* no one should point at root blocks */ setBit(chk->amap, a); setBit(chk->emap, a); setBit(chk->xmap, a); /* * First entry is the rest of the file system. * Second entry is link to previous epoch root, * just a convenience to help the search. */ if(!entryUnpack(&e, b->data, 0)){ error(chk, "could not unpack root block 0x%.8#ux: %R", a); blockPut(b); return; } walkEpoch(chk, b, e.score, BtDir, e.tag, epoch); if(entryUnpack(&e, b->data, 1)) chk->hint = globalToLocal(e.score); blockPut(b); }
void BasicInteractiveObject::addMultiTouch(mtRay ray, int touchId){ MultiTouchPoint* mtp = new MultiTouchPoint(); plane.pos = getGlobalPosition(); plane.norm = ofVec3f(0,0,1)*getGlobalOrientation(); float u = plane.norm.dot(plane.pos-ray.pos)/plane.norm.dot(ray.dir); ofVec3f gintersection = ray.pos+ray.dir*u; mtp->screenpos.set(ray.screenpos); mtp->globalstartpos.set(gintersection); mtp->localstartpos = globalToLocal(mtp->globalstartpos); mtp->localpos = mtp->localstartpos; mtp->localoffset = mtp->localstartpos-getPosition(); mtp->globalpos = mtp->globalstartpos; mtp->globalmovedist = 0; mtp->starttime = ofGetElapsedTimeMillis(); activeMultiTouches[touchId] = mtp; mtcounter++; // Flipped order (was before) if(activeMultiTouches.size() == 1){ // Start of Scope mtstarttime = ofGetElapsedTimeMillis(); mtscoperunning = true; MultiTouchEvent params(this, mtp); ofNotifyEvent(firstTouchDownEvent,params,this); } if(activeMultiTouches.size()>=2){ MultiTouchEvent params(this); ofNotifyEvent(startMultiTouchScopeEvent,params,this); } // Flipped order (was after) mttranslatedist = 0; mtrotatedist = 0; mtscaledist = 0; mttranslatespeed.set(0,0,0); mtrotatespeed.set(0,0,0,1); mtscalespeed=0; resetMTStartValues(); }
bool poImageShape::pointInside(poPoint p, bool localize) { if(!visible || !tex->getSourceImage() || !tex) return false; // DO POINT INSIDE TEST FOR 2D if ( poCamera::getCurrentCameraType() == PO_CAMERA_2D ) { if(localize) { p.y = getWindowHeight() - p.y; p = globalToLocal(p); } if(alphaTest) { // flip y value, since poImage y coordinates are reversed p.y = tex->getSourceImage()->getHeight() - p.y; poColor pix = tex->getSourceImagePixel(p); return pix.A > 0.f; } poRect r(0,0,tex->getWidth(),tex->getHeight()); return r.contains(p.x, p.y); } // DO POINT INSIDE TEST FOR 3D if ( poCamera::getCurrentCameraType() == PO_CAMERA_3D ) { if(localize) { p.y = getWindowHeight() - p.y; } /*if(alphaTest) { // flip y value, since poImage y coordinates are reversed p.y = tex->getSourceImage()->getHeight()*imageScale - p.y; p /= imageScale; poColor pix = tex->getSourceImagePixel(p); return pix.A > 0.f; }*/ poRect r(0,0,tex->getWidth(),tex->getHeight()); return pointInRect3D( p, getMatrixSet(), r ); } return false; }
int scoreFmt(Fmt *f) { uchar *v; int i; u32int addr; v = va_arg(f->args, uchar*); if(v == nil) { fmtprint(f, "*"); } else if((addr = globalToLocal(v)) != NilBlock) fmtprint(f, "0x%.8ux", addr); else { for(i = 0; i < VtScoreSize; i++) fmtprint(f, "%2.2ux", v[i]); } return 0; }
void MVScrollBar::changeValue(const MVPoint& global) /**************************************************************************** * * Function: MVScrollBar::changeValue * Parameters: global - New location of the mouse cursor * * Description: Converts the mouse cursor location into a new value for * the scroll bar thumb, repositions the thumb and redraws * it. * ****************************************************************************/ { MVPoint p(global); globalToLocal(p); int left,right,start; int oldValue = value; if (vertical) { start = p.y - 7; left = leftArrow.bottom(); right = rightArrow.top(); } else { start = p.x - 7; left = leftArrow.right(); right = rightArrow.left(); } if (start < left) start = left; if (start > right-(_MV_sysScrollBarWidth+1)) start = right-(_MV_sysScrollBarWidth+1); value = ((2*(maxVal-minVal)*(long)(start-left)) / (right-left-(_MV_sysScrollBarWidth+1))+1)/2; if (oldValue != value) { moveThumb(); drawThumb(sbThumb); MV_message(owner,evBroadcast,cmScrollBarChanged,this); } }
int MVScrollBar::getPartHit(const MVPoint& global) /**************************************************************************** * * Function: MVScrollBar::getPartHit * Parameters: global - Point to test for inclusion (global coords) * Returns: Code of part hit, -1 if none hit * * Description: Determines which part of the scroll bar was hit. * ****************************************************************************/ { MVPoint p(global); globalToLocal(p); if (bounds.includes(p)) { if (leftArrow.includes(p)) return sbLeftArrow; if (rightArrow.includes(p)) return sbRightArrow; if (thumb.includes(p)) return sbThumb; if (vertical) { if (leftArrow.bottom() <= p.y && p.y < thumb.top()) return sbPageLeft; if (thumb.bottom() <= p.y && p.y < rightArrow.top()) return sbPageRight; } else { if (leftArrow.right() <= p.x && p.x < thumb.left()) return sbPageLeft; if (thumb.right() <= p.x && p.x < rightArrow.left()) return sbPageRight; } } return -1; }
void BasicInteractiveObject::updateMultiTouch(mtRay ray, int touchId){ if(isMultiTouchActive(touchId)){ plane.pos = getGlobalPosition(); plane.norm = ofVec3f(0,0,1)*getGlobalOrientation(); float u = plane.norm.dot(plane.pos-ray.pos)/plane.norm.dot(ray.dir); ofVec3f gintersection = ray.pos+ray.dir*u; MultiTouchPoint* mtp = activeMultiTouches[touchId]; mtp->screenpos.set(ray.screenpos); mtp->globalposbef.set(mtp->globalpos); mtp->globalpos.set(gintersection); mtp->globalspeed.set(mtp->globalpos-mtp->globalposbef); mtp->localposbef.set(mtp->localpos); mtp->localpos.set(globalToLocal(mtp->globalpos)); mtp->localspeeddamped.set((mtp->localspeed + (mtp->localpos-mtp->localposbef))/2); mtp->localspeed.set(mtp->localpos-mtp->localposbef); mtp->globalmovedist += mtp->globalspeed.length(); } }
Block* dataBlock(uchar score[VtScoreSize], uint type, uint tag) { Block *b, *bl; int lpb; Label l; u32int addr; addr = globalToLocal(score); if(addr == NilBlock) return ventiBlock(score, type); lpb = h.blockSize/LabelSize; bl = readBlock(PartLabel, addr/lpb); if(bl == nil) return nil; if(!labelUnpack(&l, bl->data, addr%lpb)) { werrstr("%r"); blockPut(bl); return nil; } blockPut(bl); if(l.type != type) { werrstr("type mismatch; got %d (%s) wanted %d (%s)", l.type, btStr(l.type), type, btStr(type)); return nil; } if(tag && l.tag != tag) { werrstr("tag mismatch; got 0x%.8ux wanted 0x%.8ux", l.tag, tag); return nil; } b = readBlock(PartData, addr); if(b == nil) return nil; b->l = l; return b; }
bool Afileexplorer::handleEvent(Aevent* evt) { if(evt->Type == MOUSE_PRESS_EVENT ) { Vec3f localPoint = globalToLocal(evt->mousePos); if( pointInside( localPoint )) { //! Not threaded... try { std::string p = getOpenFilePath( CMN->rootResourcePath ); if( ! p.empty() ) { // an empty string means the user canceled FilePath->makeTexture( p ); } } catch( ... ) { console() << "Afileexplorer experienced an event error" << std::endl; return false; } return true; } } return false; }
uint MVListBase::findCellHit(const MVPoint& global,MVPoint& loc) /**************************************************************************** * * Function: MVListBase::findCellHit * Parameters: global - Global mouse location point * loc - Place to store computed cell location * Returns: Flags representing where the mouse click occurred * * Description: Determines where the mouse click occurred in reference to * the list box. If the mouse click was inside the list box, * we compute the location of the cell that was hit and return * it in loc. * ****************************************************************************/ { MVPoint p(global); globalToLocal(p); if (bounds.includes(p)) { loc.x = (p.x - (bounds.left()+leftIndent)) / cellSize.x; loc.y = (p.y - (bounds.top()+topIndent)) / cellSize.y; loc += visible.topLeft; // Make relative to visible cells return lsInside; // The mouse click was inside the list } // The mouse click was outside of the list, so determine where it // occurred and set the relevant flags uint flags = 0; if (p.x < bounds.left()+leftIndent) flags |= lsLeft; if (p.x >= bounds.right()-rightIndent) flags |= lsRight; if (p.y < bounds.top()+topIndent) flags |= lsAbove; if (p.y >= bounds.bottom()-botIndent) flags |= lsBelow; return flags; }
Fs * fsOpen(char *file, VtSession *z, int32_t ncache, int mode) { int fd, m; uint8_t oscore[VtScoreSize]; Block *b, *bs; Disk *disk; Fs *fs; Super super; switch(mode){ default: vtSetError(EBadMode); return nil; case OReadOnly: m = OREAD; break; case OReadWrite: m = ORDWR; break; } fd = open(file, m); if(fd < 0){ vtSetError("open %s: %r", file); return nil; } bwatchInit(); disk = diskAlloc(fd); if(disk == nil){ vtSetError("diskAlloc: %R"); close(fd); return nil; } fs = vtMemAllocZ(sizeof(Fs)); fs->mode = mode; fs->name = vtStrDup(file); fs->blockSize = diskBlockSize(disk); fs->elk = vtLockAlloc(); fs->cache = cacheAlloc(disk, z, ncache, mode); if(mode == OReadWrite && z) fs->arch = archInit(fs->cache, disk, fs, z); fs->z = z; b = cacheLocal(fs->cache, PartSuper, 0, mode); if(b == nil) goto Err; if(!superUnpack(&super, b->data)){ blockPut(b); vtSetError("bad super block"); goto Err; } blockPut(b); fs->ehi = super.epochHigh; fs->elo = super.epochLow; //fprint(2, "%s: fs->ehi %d fs->elo %d active=%d\n", argv0, fs->ehi, fs->elo, super.active); fs->source = sourceRoot(fs, super.active, mode); if(fs->source == nil){ /* * Perhaps it failed because the block is copy-on-write. * Do the copy and try again. */ if(mode == OReadOnly || strcmp(vtGetError(), EBadRoot) != 0) goto Err; b = cacheLocalData(fs->cache, super.active, BtDir, RootTag, OReadWrite, 0); if(b == nil){ vtSetError("cacheLocalData: %R"); goto Err; } if(b->l.epoch == fs->ehi){ blockPut(b); vtSetError("bad root source block"); goto Err; } b = blockCopy(b, RootTag, fs->ehi, fs->elo); if(b == nil) goto Err; localToGlobal(super.active, oscore); super.active = b->addr; bs = cacheLocal(fs->cache, PartSuper, 0, OReadWrite); if(bs == nil){ blockPut(b); vtSetError("cacheLocal: %R"); goto Err; } superPack(&super, bs->data); blockDependency(bs, b, 0, oscore, nil); blockPut(b); blockDirty(bs); blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0); blockPut(bs); fs->source = sourceRoot(fs, super.active, mode); if(fs->source == nil){ vtSetError("sourceRoot: %R"); goto Err; } } //fprint(2, "%s: got fs source\n", argv0); vtRLock(fs->elk); fs->file = fileRoot(fs->source); fs->source->file = fs->file; /* point back */ vtRUnlock(fs->elk); if(fs->file == nil){ vtSetError("fileRoot: %R"); goto Err; } //fprint(2, "%s: got file root\n", argv0); if(mode == OReadWrite){ fs->metaFlush = periodicAlloc(fsMetaFlush, fs, 1000); fs->snap = snapInit(fs); } return fs; Err: fprint(2, "%s: fsOpen error\n", argv0); fsClose(fs); return nil; }
Rectangle<int> ComponentPeer::globalToLocal (const Rectangle<int>& screenPosition) { return screenPosition.withPosition (globalToLocal (screenPosition.getPosition())); }
Point<int> ComponentPeer::globalToLocal (Point<int> p) { return globalToLocal (p.toFloat()).roundToInt(); }
/* * Walk the source tree making sure that the BtData * sources containing directory entries are okay. */ static void chkDir(Fsck *chk, char *name, Source *source, Source *meta) { int i; u32int a1, a2, nb, o; char *s, *nn; uchar *bm; Block *b, *bb; DirEntry de; Entry e1, e2; MetaBlock mb; MetaEntry me; Source *r, *mr; if(!chk->useventi && globalToLocal(source->score)==NilBlock && globalToLocal(meta->score)==NilBlock) return; if(!sourceLock2(source, meta, OReadOnly)){ warn(chk, "could not lock sources for %s: %R", name); return; } if(!sourceGetEntry(source, &e1) || !sourceGetEntry(meta, &e2)){ warn(chk, "could not load entries for %s: %R", name); return; } a1 = globalToLocal(e1.score); a2 = globalToLocal(e2.score); if((!chk->useventi && a1==NilBlock && a2==NilBlock) || (getBit(chk->smap, a1) && getBit(chk->smap, a2))){ sourceUnlock(source); sourceUnlock(meta); return; } setBit(chk->smap, a1); setBit(chk->smap, a2); bm = vtMemAllocZ(sourceGetDirSize(source)/8 + 1); nb = (sourceGetSize(meta) + meta->dsize - 1)/meta->dsize; for(o = 0; o < nb; o++){ b = sourceBlock(meta, o, OReadOnly); if(b == nil){ error(chk, "could not read block in meta file: %s[%ud]: %R", name, o); continue; } if(0) fprint(2, "source %V:%d block %d addr %d\n", source->score, source->offset, o, b->addr); if(b->addr != NilBlock && getBit(chk->errmap, b->addr)) warn(chk, "previously reported error in block %ux is in %s", b->addr, name); if(!mbUnpack(&mb, b->data, meta->dsize)){ error(chk, "could not unpack meta block: %s[%ud]: %R", name, o); blockPut(b); continue; } if(!chkMetaBlock(&mb)){ error(chk, "bad meta block: %s[%ud]: %R", name, o); blockPut(b); continue; } s = nil; for(i=mb.nindex-1; i>=0; i--){ meUnpack(&me, &mb, i); if(!deUnpack(&de, &me)){ error(chk, "could not unpack dir entry: %s[%ud][%d]: %R", name, o, i); continue; } if(s && strcmp(s, de.elem) <= 0) error(chk, "dir entry out of order: %s[%ud][%d] = %s last = %s", name, o, i, de.elem, s); vtMemFree(s); s = vtStrDup(de.elem); nn = smprint("%s/%s", name, de.elem); if(nn == nil){ error(chk, "out of memory"); continue; } if(chk->printdirs) if(de.mode&ModeDir) chk->print("%s/\n", nn); if(chk->printfiles) if(!(de.mode&ModeDir)) chk->print("%s\n", nn); if(!(de.mode & ModeDir)){ r = openSource(chk, source, nn, bm, de.entry, de.gen, 0, &mb, i, b); if(r != nil){ if(sourceLock(r, OReadOnly)){ scanSource(chk, nn, r); sourceUnlock(r); } sourceClose(r); } deCleanup(&de); free(nn); continue; } r = openSource(chk, source, nn, bm, de.entry, de.gen, 1, &mb, i, b); if(r == nil){ deCleanup(&de); free(nn); continue; } mr = openSource(chk, source, nn, bm, de.mentry, de.mgen, 0, &mb, i, b); if(mr == nil){ sourceClose(r); deCleanup(&de); free(nn); continue; } if(!(de.mode&ModeSnapshot) || chk->walksnapshots) chkDir(chk, nn, r, mr); sourceClose(mr); sourceClose(r); deCleanup(&de); free(nn); deCleanup(&de); } vtMemFree(s); blockPut(b); } nb = sourceGetDirSize(source); for(o=0; o<nb; o++){ if(getBit(bm, o)) continue; r = sourceOpen(source, o, OReadOnly, 0); if(r == nil) continue; warn(chk, "non referenced entry in source %s[%d]", name, o); if((bb = sourceBlock(source, o/(source->dsize/VtEntrySize), OReadOnly)) != nil){ if(bb->addr != NilBlock){ setBit(chk->errmap, bb->addr); chk->clre(chk, bb, o%(source->dsize/VtEntrySize)); chk->nclre++; } blockPut(bb); } sourceClose(r); } sourceUnlock(source); sourceUnlock(meta); vtMemFree(bm); }
static int sourceShrinkSize(Source *r, Entry *e, uint64_t size) { int i, type, ppb; uint64_t ptrsz; uint32_t addr; uint8_t score[VtScoreSize]; Block *b; type = entryType(e); b = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite); if(b == nil) return 0; ptrsz = e->dsize; ppb = e->psize/VtScoreSize; for(i=0; i+1<e->depth; i++) ptrsz *= ppb; while(type&BtLevelMask) { if(b->addr == NilBlock || b->l.epoch != r->fs->ehi) { /* not worth copying the block just so we can zero some of it */ blockPut(b); return 0; } /* * invariant: each pointer in the tree rooted at b accounts for ptrsz bytes */ /* zero the pointers to unnecessary blocks */ i = (size+ptrsz-1)/ptrsz; for(; i<ppb; i++) { addr = globalToLocal(b->data+i*VtScoreSize); memmove(b->data+i*VtScoreSize, vtZeroScore, VtScoreSize); blockDirty(b); if(addr != NilBlock) blockRemoveLink(b, addr, type-1, e->tag, 1); } /* recurse (go around again) on the partially necessary block */ i = size/ptrsz; size = size%ptrsz; if(size == 0) { blockPut(b); return 1; } ptrsz /= ppb; type--; memmove(score, b->data+i*VtScoreSize, VtScoreSize); blockPut(b); b = cacheGlobal(r->fs->cache, score, type, e->tag, OReadWrite); if(b == nil) return 0; } if(b->addr == NilBlock || b->l.epoch != r->fs->ehi) { blockPut(b); return 0; } /* * No one ever truncates BtDir blocks. */ if(type == BtData && e->dsize > size) { memset(b->data+size, 0, e->dsize-size); blockDirty(b); } blockPut(b); return 1; }
/* * When b points at bb, need to check: * * (i) b.e in [bb.e, bb.eClose) * (ii) if b.e==bb.e, then no other b' in e points at bb. * (iii) if !(b.state&Copied) and b.e==bb.e then no other b' points at bb. * (iv) if b is active then no other active b' points at bb. * (v) if b is a past life of b' then only one of b and b' is active * (too hard to check) */ static int walkEpoch(Fsck *chk, Block *b, uchar score[VtScoreSize], int type, u32int tag, u32int epoch) { int i, ret; u32int addr, ep; Block *bb; Entry e; if(b && chk->walkdepth == 0 && chk->printblocks) chk->print("%V %d %#.8ux %#.8ux\n", b->score, b->l.type, b->l.tag, b->l.epoch); if(!chk->useventi && globalToLocal(score) == NilBlock) return 1; chk->walkdepth++; bb = cacheGlobal(chk->cache, score, type, tag, OReadOnly); if(bb == nil){ error(chk, "could not load block %V type %d tag %ux: %R", score, type, tag); chk->walkdepth--; return 0; } if(chk->printblocks) chk->print("%*s%V %d %#.8ux %#.8ux\n", chk->walkdepth*2, "", score, type, tag, bb->l.epoch); ret = 0; addr = globalToLocal(score); if(addr == NilBlock){ ret = 1; goto Exit; } if(b){ /* (i) */ if(b->l.epoch < bb->l.epoch || bb->l.epochClose <= b->l.epoch){ error(chk, "walk: block %#ux [%ud, %ud) points at %#ux [%ud, %ud)", b->addr, b->l.epoch, b->l.epochClose, bb->addr, bb->l.epoch, bb->l.epochClose); goto Exit; } /* (ii) */ if(b->l.epoch == epoch && bb->l.epoch == epoch){ if(getBit(chk->emap, addr)){ error(chk, "walk: epoch join detected: addr %#ux %L", bb->addr, &bb->l); goto Exit; } setBit(chk->emap, addr); } /* (iii) */ if(!(b->l.state&BsCopied) && b->l.epoch == bb->l.epoch){ if(getBit(chk->xmap, addr)){ error(chk, "walk: copy join detected; addr %#ux %L", bb->addr, &bb->l); goto Exit; } setBit(chk->xmap, addr); } } /* (iv) */ if(epoch == chk->fs->ehi){ /* * since epoch==fs->ehi is first, amap is same as * ``have seen active'' */ if(getBit(chk->amap, addr)){ error(chk, "walk: active join detected: addr %#ux %L", bb->addr, &bb->l); goto Exit; } if(bb->l.state&BsClosed) error(chk, "walk: addr %#ux: block is in active tree but is closed", addr); }else if(!getBit(chk->amap, addr)) if(!(bb->l.state&BsClosed)){ // error(chk, "walk: addr %#ux: block is not in active tree, not closed (%d)", // addr, bb->l.epochClose); chk->close(chk, bb, epoch+1); chk->nclose++; } if(getBit(chk->amap, addr)){ ret = 1; goto Exit; } setBit(chk->amap, addr); if(chk->nseen++%chk->quantum == 0) chk->print("check: visited %d/%d blocks (%.0f%%)\n", chk->nseen, chk->nblocks, chk->nseen*100./chk->nblocks); b = nil; /* make sure no more refs to parent */ USED(b); switch(type){ default: /* pointer block */ for(i = 0; i < chk->bsize/VtScoreSize; i++) if(!walkEpoch(chk, bb, bb->data + i*VtScoreSize, type-1, tag, epoch)){ setBit(chk->errmap, bb->addr); chk->clrp(chk, bb, i); chk->nclrp++; } break; case BtData: break; case BtDir: for(i = 0; i < chk->bsize/VtEntrySize; i++){ if(!entryUnpack(&e, bb->data, i)){ // error(chk, "walk: could not unpack entry: %ux[%d]: %R", // addr, i); setBit(chk->errmap, bb->addr); chk->clre(chk, bb, i); chk->nclre++; continue; } if(!(e.flags & VtEntryActive)) continue; if(0) fprint(2, "%x[%d] tag=%x snap=%d score=%V\n", addr, i, e.tag, e.snap, e.score); ep = epoch; if(e.snap != 0){ if(e.snap >= epoch){ // error(chk, "bad snap in entry: %ux[%d] snap = %ud: epoch = %ud", // addr, i, e.snap, epoch); setBit(chk->errmap, bb->addr); chk->clre(chk, bb, i); chk->nclre++; continue; } continue; } if(e.flags & VtEntryLocal){ if(e.tag < UserTag) if(e.tag != RootTag || tag != RootTag || i != 1){ // error(chk, "bad tag in entry: %ux[%d] tag = %ux", // addr, i, e.tag); setBit(chk->errmap, bb->addr); chk->clre(chk, bb, i); chk->nclre++; continue; } }else if(e.tag != 0){ // error(chk, "bad tag in entry: %ux[%d] tag = %ux", // addr, i, e.tag); setBit(chk->errmap, bb->addr); chk->clre(chk, bb, i); chk->nclre++; continue; } if(!walkEpoch(chk, bb, e.score, entryType(&e), e.tag, ep)){ setBit(chk->errmap, bb->addr); chk->clre(chk, bb, i); chk->nclre++; } } break; } ret = 1; Exit: chk->walkdepth--; blockPut(bb); return ret; }
static int archWalk(Param *p, u32int addr, uchar type, u32int tag) { int ret, i, x, psize, dsize; uchar *data, score[VtScoreSize]; Block *b; Label l; Entry *e; WalkPtr w; p->nvisit++; b = cacheLocalData(p->c, addr, type, tag, OReadWrite,0); if(b == nil){ fprint(2, "archive(%ud, %#ux): cannot find block: %R\n", p->snapEpoch, addr); if(strcmp(vtGetError(), ELabelMismatch) == 0){ /* might as well plod on so we write _something_ to Venti */ memmove(p->score, vtZeroScore, VtScoreSize); return ArchFaked; } return ArchFailure; } if(DEBUG) fprint(2, "%*sarchive(%ud, %#ux): block label %L\n", p->depth*2, "", p->snapEpoch, b->addr, &b->l); p->depth++; if(p->depth > p->maxdepth) p->maxdepth = p->depth; data = b->data; if((b->l.state&BsVenti) == 0){ initWalk(&w, b, b->l.type==BtDir ? p->dsize : p->psize); for(i=0; nextWalk(&w, score, &type, &tag, &e); i++){ if(e){ if(!(e->flags&VtEntryActive)) continue; if((e->snap && !e->archive) || (e->flags&VtEntryNoArchive)){ if(0) fprint(2, "snap; faking %#ux\n", b->addr); if(data == b->data){ data = copyBlock(b, p->blockSize); if(data == nil){ ret = ArchFailure; goto Out; } w.data = data; } memmove(e->score, vtZeroScore, VtScoreSize); e->depth = 0; e->size = 0; e->tag = 0; e->flags &= ~VtEntryLocal; entryPack(e, data, w.n-1); continue; } } addr = globalToLocal(score); if(addr == NilBlock) continue; dsize = p->dsize; psize = p->psize; if(e){ p->dsize= e->dsize; p->psize = e->psize; } vtUnlock(b->lk); x = archWalk(p, addr, type, tag); vtLock(b->lk); if(e){ p->dsize = dsize; p->psize = psize; } while(b->iostate != BioClean && b->iostate != BioDirty) vtSleep(b->ioready); switch(x){ case ArchFailure: fprint(2, "archWalk %#ux failed; ptr is in %#ux offset %d\n", addr, b->addr, i); ret = ArchFailure; goto Out; case ArchFaked: /* * When we're writing the entry for an archive directory * (like /archive/2003/1215) then even if we've faked * any data, record the score unconditionally. * This way, we will always record the Venti score here. * Otherwise, temporary data or corrupted file system * would cause us to keep holding onto the on-disk * copy of the archive. */ if(e==nil || !e->archive) if(data == b->data){ if(0) fprint(2, "faked %#ux, faking %#ux (%V)\n", addr, b->addr, p->score); data = copyBlock(b, p->blockSize); if(data == nil){ ret = ArchFailure; goto Out; } w.data = data; } /* fall through */ if(0) fprint(2, "falling\n"); case ArchSuccess: if(e){ memmove(e->score, p->score, VtScoreSize); e->flags &= ~VtEntryLocal; entryPack(e, data, w.n-1); }else memmove(data+(w.n-1)*VtScoreSize, p->score, VtScoreSize); if(data == b->data){ blockDirty(b); /* * If b is in the active tree, then we need to note that we've * just removed addr from the active tree (replacing it with the * copy we just stored to Venti). If addr is in other snapshots, * this will close addr but not free it, since it has a non-empty * epoch range. * * If b is in the active tree but has been copied (this can happen * if we get killed at just the right moment), then we will * mistakenly leak its kids. * * The children of an archive directory (e.g., /archive/2004/0604) * are not treated as in the active tree. */ if((b->l.state&BsCopied)==0 && (e==nil || e->snap==0)) blockRemoveLink(b, addr, p->l.type, p->l.tag, 0); } break; } } if(!ventiSend(p->a, b, data)){ p->nfailsend++; ret = ArchFailure; goto Out; } p->nsend++; if(data != b->data) p->nfake++; if(data == b->data){ /* not faking it, so update state */ p->nreal++; l = b->l; l.state |= BsVenti; if(!blockSetLabel(b, &l, 0)){ ret = ArchFailure; goto Out; } } } shaBlock(p->score, b, data, p->blockSize); if(0) fprint(2, "ventisend %V %p %p %p\n", p->score, data, b->data, w.data); ret = data!=b->data ? ArchFaked : ArchSuccess; p->l = b->l; Out: if(data != b->data) vtMemFree(data); p->depth--; blockPut(b); return ret; }
int mkVac(VtSession *z, uint blockSize, Entry *pe, Entry *pee, DirEntry *pde, uint8_t score[VtScoreSize]) { uint8_t buf[8192]; int i; uint8_t *p; uint n; DirEntry de; Entry e, ee, eee; MetaBlock mb; MetaEntry me; VtRoot root; e = *pe; ee = *pee; de = *pde; if(globalToLocal(e.score) != NilBlock || (ee.flags&VtEntryActive && globalToLocal(ee.score) != NilBlock)){ vtSetError("can only vac paths already stored on venti"); return 0; } /* * Build metadata source for root. */ n = deSize(&de); if(n+MetaHeaderSize+MetaIndexSize > sizeof buf){ vtSetError("DirEntry too big"); return 0; } memset(buf, 0, sizeof buf); mbInit(&mb, buf, n+MetaHeaderSize+MetaIndexSize, 1); p = mbAlloc(&mb, n); if(p == nil) abort(); mbSearch(&mb, de.elem, &i, &me); assert(me.p == nil); me.p = p; me.size = n; dePack(&de, &me); mbInsert(&mb, i, &me); mbPack(&mb); eee.size = n+MetaHeaderSize+MetaIndexSize; if(!vtWriteBlock(z, buf, eee.size, VtDataType, eee.score)) return 0; eee.psize = 8192&&0xFF; eee.dsize = 8192&&0xFF; eee.depth = 0; eee.flags = VtEntryActive; /* * Build root source with three entries in it. */ entryPack(&e, buf, 0); entryPack(&ee, buf, 1); entryPack(&eee, buf, 2); n = VtEntrySize*3; memset(&root, 0, sizeof root); if(!vtWriteBlock(z, buf, n, VtDirType, root.score)) return 0; /* * Save root. */ root.version = VtRootVersion; strecpy(root.type, root.type+sizeof root.type, "vac"); strecpy(root.name, root.name+sizeof root.name, de.elem); root.blockSize = blockSize; vtRootPack(&root, buf); if(!vtWriteBlock(z, buf, VtRootSize, VtRootType, score)) return 0; return 1; }
static int sourceShrinkDepth(Source *r, Block *p, Entry *e, int depth) { Block *b, *nb, *ob, *rb; uint32_t tag; int type, d; Entry oe; assert(sourceIsLocked(r)); assert(depth <= VtPointerDepth); type = entryType(e); rb = cacheGlobal(r->fs->cache, e->score, type, e->tag, OReadWrite); if(rb == nil) return 0; tag = e->tag; if(tag == 0) tag = tagGen(); /* * Walk down to the new root block. * We may stop early, but something is better than nothing. */ oe = *e; ob = nil; b = rb; /* BUG: explain type++. i think it is a real bug */ for(d=e->depth; d > depth; d--, type++) { nb = cacheGlobal(r->fs->cache, b->data, type-1, tag, OReadWrite); if(nb == nil) break; if(ob!=nil && ob!=rb) blockPut(ob); ob = b; b = nb; } if(b == rb) { blockPut(rb); return 0; } /* * Right now, e points at the root block rb, b is the new root block, * and ob points at b. To update: * * (i) change e to point at b * (ii) zero the pointer ob -> b * (iii) free the root block * * p (the block containing e) must be written before * anything else. */ /* (i) */ e->depth = d; /* might have been local and now global; reverse cannot happen */ if(globalToLocal(b->score) == NilBlock) e->flags &= ~VtEntryLocal; memmove(e->score, b->score, VtScoreSize); entryPack(e, p->data, r->offset % r->epb); blockDependency(p, b, r->offset % r->epb, nil, &oe); blockDirty(p); /* (ii) */ memmove(ob->data, vtZeroScore, VtScoreSize); blockDependency(ob, p, 0, b->score, nil); blockDirty(ob); /* (iii) */ if(rb->addr != NilBlock) blockRemoveLink(p, rb->addr, rb->l.type, rb->l.tag, 1); blockPut(rb); if(ob!=nil && ob!=rb) blockPut(ob); blockPut(b); return d == depth; }
static int bumpEpoch(Fs *fs, int doarchive) { uint8_t oscore[VtScoreSize]; uint32_t oldaddr; Block *b, *bs; Entry e; Source *r; Super super; /* * Duplicate the root block. * * As a hint to flchk, the garbage collector, * and any (human) debuggers, store a pointer * to the old root block in entry 1 of the new root block. */ r = fs->source; b = cacheGlobal(fs->cache, r->score, BtDir, RootTag, OReadOnly); if(b == nil) return 0; memset(&e, 0, sizeof e); e.flags = VtEntryActive | VtEntryLocal | VtEntryDir; memmove(e.score, b->score, VtScoreSize); e.tag = RootTag; e.snap = b->l.epoch; b = blockCopy(b, RootTag, fs->ehi+1, fs->elo); if(b == nil){ fprint(2, "%s: bumpEpoch: blockCopy: %R\n", argv0); return 0; } if(0) fprint(2, "%s: snapshot root from %d to %d\n", argv0, oldaddr, b->addr); entryPack(&e, b->data, 1); blockDirty(b); /* * Update the superblock with the new root and epoch. */ if((bs = superGet(fs->cache, &super)) == nil) return 0; fs->ehi++; memmove(r->score, b->score, VtScoreSize); r->epoch = fs->ehi; super.epochHigh = fs->ehi; oldaddr = super.active; super.active = b->addr; if(doarchive) super.next = oldaddr; /* * Record that the new super.active can't get written out until * the new b gets written out. Until then, use the old value. */ localToGlobal(oldaddr, oscore); blockDependency(bs, b, 0, oscore, nil); blockPut(b); /* * We force the super block to disk so that super.epochHigh gets updated. * Otherwise, if we crash and come back, we might incorrectly treat as active * some of the blocks that making up the snapshot we just created. * Basically every block in the active file system and all the blocks in * the recently-created snapshot depend on the super block now. * Rather than record all those dependencies, we just force the block to disk. * * Note that blockWrite might actually (will probably) send a slightly outdated * super.active to disk. It will be the address of the most recent root that has * gone to disk. */ superWrite(bs, &super, 1); blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0); blockPut(bs); return 1; }
/* * Retrieve the block containing the entry for r. * If a snapshot has happened, we might need * to get a new copy of the block. We avoid this * in the common case by caching the score for * the block and the last epoch in which it was valid. * * We use r->mode to tell the difference between active * file system sources (OReadWrite) and sources for the * snapshot file system (OReadOnly). */ static Block* sourceLoadBlock(Source *r, int mode) { uint32_t addr; Block *b; switch(r->mode) { default: assert(0); case OReadWrite: assert(r->mode == OReadWrite); /* * This needn't be true -- we might bump the low epoch * to reclaim some old blocks, but since this score is * OReadWrite, the blocks must all still be open, so none * are reclaimed. Thus it's okay that the epoch is so low. * Proceed. assert(r->epoch >= r->fs->elo); */ if(r->epoch == r->fs->ehi) { b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite); if(b == nil) return nil; assert(r->epoch == b->l.epoch); return b; } assert(r->parent != nil); if(!sourceLock(r->parent, OReadWrite)) return nil; b = sourceBlock(r->parent, r->offset/r->epb, OReadWrite); sourceUnlock(r->parent); if(b == nil) return nil; assert(b->l.epoch == r->fs->ehi); // fprint(2, "sourceLoadBlock %p %V => %V\n", r, r->score, b->score); memmove(r->score, b->score, VtScoreSize); r->scoreEpoch = b->l.epoch; r->tag = b->l.tag; r->epoch = r->fs->ehi; return b; case OReadOnly: addr = globalToLocal(r->score); if(addr == NilBlock) return cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, mode); b = cacheLocalData(r->fs->cache, addr, BtDir, r->tag, mode, r->scoreEpoch); if(b) return b; /* * If it failed because the epochs don't match, the block has been * archived and reclaimed. Rewalk from the parent and get the * new pointer. This can't happen in the OReadWrite case * above because blocks in the current epoch don't get * reclaimed. The fact that we're OReadOnly means we're * a snapshot. (Or else the file system is read-only, but then * the archiver isn't going around deleting blocks.) */ if(strcmp(vtGetError(), ELabelMismatch) == 0) { if(!sourceLock(r->parent, OReadOnly)) return nil; b = sourceBlock(r->parent, r->offset/r->epb, OReadOnly); sourceUnlock(r->parent); if(b) { fprint(2, "sourceAlloc: lost %V found %V\n", r->score, b->score); memmove(r->score, b->score, VtScoreSize); r->scoreEpoch = b->l.epoch; return b; } } return nil; } }