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  }