github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/blobserver/diskpacked/dele.go (about) 1 /* 2 Copyright 2013 The Camlistore Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package diskpacked 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "io" 24 "os" 25 "strconv" 26 27 "camlistore.org/pkg/blob" 28 ) 29 30 var errNoPunch = errors.New("punchHole not supported") 31 32 // punchHole, if non-nil, punches a hole in f from offset to offset+size. 33 var punchHole func(file *os.File, offset int64, size int64) error 34 35 func (s *storage) delete(br blob.Ref) error { 36 meta, err := s.meta(br) 37 if err != nil { 38 return err 39 } 40 f, err := os.OpenFile(s.filename(meta.file), os.O_RDWR, 0666) 41 if err != nil { 42 return err 43 } 44 defer f.Close() 45 46 // walk back, find the header, and overwrite the hash with xxxx-000000... 47 k := 1 + len(br.String()) + 1 + len(strconv.FormatUint(uint64(meta.size), 10)) + 1 48 off := meta.offset - int64(k) 49 b := make([]byte, k) 50 if k, err = f.ReadAt(b, off); err != nil { 51 return err 52 } 53 if b[0] != byte('[') || b[k-1] != byte(']') { 54 return fmt.Errorf("delete: cannot find header surroundings, found %q", b) 55 } 56 b = b[1 : k-1] // "sha1-xxxxxxxxxxxxxxxxxx nnnn" - everything between [] 57 off += 1 58 59 // Replace b with "xxxx-000000000" 60 dash := bytes.IndexByte(b, '-') 61 if dash < 0 { 62 return fmt.Errorf("delete: cannot find dash in ref %q", b) 63 } 64 space := bytes.IndexByte(b[dash+1:], ' ') 65 if space < 0 { 66 return fmt.Errorf("delete: cannot find space in header %q", b) 67 } 68 for i := 0; i < dash; i++ { 69 b[i] = 'x' 70 } 71 for i := dash + 1; i < dash+1+space; i++ { 72 b[i] = '0' 73 } 74 75 // write back 76 if _, err = f.WriteAt(b, off); err != nil { 77 return err 78 } 79 80 // punch hole, if possible 81 if punchHole != nil { 82 err = punchHole(f, meta.offset, int64(meta.size)) 83 if err == nil { 84 return nil 85 } 86 if err != errNoPunch { 87 return err 88 } 89 // err == errNoPunch - not implemented 90 } 91 92 // fill with zero 93 n, err := f.Seek(meta.offset, os.SEEK_SET) 94 if err != nil { 95 return err 96 } 97 if n != meta.offset { 98 return fmt.Errorf("error seeking to %d: got %d", meta.offset, n) 99 } 100 _, err = io.CopyN(f, zeroReader{}, int64(meta.size)) 101 return err 102 } 103 104 type zeroReader struct{} 105 106 func (z zeroReader) Read(p []byte) (n int, err error) { 107 for i := range p { 108 p[i] = 0 109 } 110 return len(p), nil 111 }