package blockstore_util import ( "fmt" "io" bs "github.com/ipfs/go-ipfs/blocks/blockstore" "github.com/ipfs/go-ipfs/pin" ds "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore" cid "gx/ipfs/QmcTcsTvfaeEBRFo1TkFgT8sRmgi1n1LTZpecfVP8fzpGD/go-cid" ) // RemovedBlock is used to respresent the result of removing a block. // If a block was removed successfully than the Error string will be // empty. If a block could not be removed than Error will contain the // reason the block could not be removed. If the removal was aborted // due to a fatal error Hash will be be empty, Error will contain the // reason, and no more results will be sent. type RemovedBlock struct { Hash string `json:",omitempty"` Error string `json:",omitempty"` } type RmBlocksOpts struct { Prefix string Quiet bool Force bool } func RmBlocks(blocks bs.GCBlockstore, pins pin.Pinner, out chan<- interface{}, cids []*cid.Cid, opts RmBlocksOpts) error { go func() { defer close(out) unlocker := blocks.GCLock() defer unlocker.Unlock() stillOkay := FilterPinned(pins, out, cids) for _, c := range stillOkay { err := blocks.DeleteBlock(c) if err != nil && opts.Force && (err == bs.ErrNotFound || err == ds.ErrNotFound) { // ignore non-existent blocks } else if err != nil { out <- &RemovedBlock{Hash: c.String(), Error: err.Error()} } else if !opts.Quiet { out <- &RemovedBlock{Hash: c.String()} } } }() return nil } func FilterPinned(pins pin.Pinner, out chan<- interface{}, cids []*cid.Cid) []*cid.Cid { stillOkay := make([]*cid.Cid, 0, len(cids)) res, err := pins.CheckIfPinned(cids...) if err != nil { out <- &RemovedBlock{Error: fmt.Sprintf("pin check failed: %s", err)} return nil } for _, r := range res { if !r.Pinned() { stillOkay = append(stillOkay, r.Key) } else { out <- &RemovedBlock{ Hash: r.Key.String(), Error: r.String(), } } } return stillOkay } func ProcRmOutput(in <-chan interface{}, sout io.Writer, serr io.Writer) error { someFailed := false for res := range in { r := res.(*RemovedBlock) if r.Hash == "" && r.Error != "" { return fmt.Errorf("aborted: %s", r.Error) } else if r.Error != "" { someFailed = true fmt.Fprintf(serr, "cannot remove %s: %s\n", r.Hash, r.Error) } else { fmt.Fprintf(sout, "removed %s\n", r.Hash) } } if someFailed { return fmt.Errorf("some blocks not removed") } return nil }