func (cfio *ChunkedFileIO) Truncate(size int64) error { if !fl.IsReadWriteAllowed(cfio.bs.Flags()) { return EPERM } cs, err := cfio.caio.Read() if err != nil { return fmt.Errorf("Failed to read cs array: %v", err) } for i := len(cs) - 1; i >= 0; i-- { c := &cs[i] if c.Left() >= size { // drop the chunk continue } if c.Right() > size { // trim the chunk chunksize := size - c.Left() bh, err := cfio.bs.Open(c.BlobPath, fl.O_RDWR) if err != nil { return err } cio := cfio.newChunkIO(bh, cfio.c, c.Offset) if err := cio.Truncate(chunksize); err != nil { return err } if err := cio.Close(); err != nil { return err } c.Length = int64(cio.Size()) } cs = cs[:i+1] if err := cfio.caio.Write(cs); err != nil { return fmt.Errorf("Failed to write updated cs array: %v", err) } return nil } if err := cfio.caio.Write([]inodedb.FileChunk{}); err != nil { return fmt.Errorf("Failed to write updated cs array (empty): %v", err) } return nil }
func (cfio *ChunkedFileIO) PWrite(p []byte, offset int64) error { logger.Debugf(mylog, "PWrite: offset=%d, len=%d", offset, len(p)) // logger.Debugf(mylog, "PWrite: p=%v", p) remo := offset remp := p if len(remp) == 0 { return nil } cs, err := cfio.caio.Read() if err != nil { return fmt.Errorf("Failed to read cs array: %v", err) } writeToChunk := func(c *inodedb.FileChunk, isNewChunk bool, maxChunkLen int64) error { if !fl.IsReadWriteAllowed(cfio.bs.Flags()) { return EPERM } flags := fl.O_RDWR if isNewChunk { flags |= fl.O_CREATE | fl.O_EXCL } bh, err := cfio.bs.Open(c.BlobPath, flags) if err != nil { return fmt.Errorf("Failed to open path \"%s\" for writing (isNewChunk: %t): %v", c.BlobPath, isNewChunk, err) } defer func() { if err := bh.Close(); err != nil { logger.Criticalf(mylog, "blobhandle Close failed: %v", err) } }() cio := cfio.newChunkIO(bh, cfio.c, c.Offset) defer func() { if err := cio.Close(); err != nil { logger.Criticalf(mylog, "cio Close failed: %v", err) } }() coff := remo - c.Offset n := util.IntMin(len(remp), int(maxChunkLen-coff)) if n < 0 { return nil } if err := cio.PWrite(remp[:n], coff); err != nil { return err } oldLength := c.Length c.Length = int64(cio.Size()) if oldLength != c.Length { if err := cfio.caio.Write(cs); err != nil { return fmt.Errorf("Failed to write updated cs array: %v", err) } } remo += int64(n) remp = remp[n:] return nil } for i := 0; i < len(cs); i++ { c := &cs[i] if c.Left() > remo { // Insert a new chunk @ i // try best to align offset at ChunkSplitSize newo := remo / ChunkSplitSize * ChunkSplitSize maxlen := int64(ChunkSplitSize) if i > 0 { prev := cs[i-1] pright := prev.Right() if newo < pright { maxlen -= pright - newo newo = pright } } if i < len(cs)-1 { next := cs[i+1] if newo+maxlen > next.Left() { maxlen = next.Left() - newo } } newc, err := cfio.newFileChunk(newo) if err != nil { return err } cs = append(cs, inodedb.FileChunk{}) copy(cs[i+1:], cs[i:]) cs[i] = newc if err := cfio.caio.Write(cs); err != nil { return fmt.Errorf("Failed to write updated cs array: %v", err) } if err := writeToChunk(&newc, NewChunk, maxlen); err != nil { return err } if len(remp) == 0 { break } continue } // Write to the chunk maxlen := int64(ChunkSplitSize) if i < len(cs)-1 { next := cs[i+1] if c.Left()+maxlen > next.Left() { maxlen = next.Left() - c.Left() } } if err := writeToChunk(c, ExistingChunk, maxlen); err != nil { return err } if len(remp) == 0 { break } } for len(remp) > 0 { // Append a new chunk at the end newo := remo / ChunkSplitSize * ChunkSplitSize maxlen := int64(ChunkSplitSize) if len(cs) > 0 { last := cs[len(cs)-1] lastRight := last.Right() if newo < lastRight { maxlen -= lastRight - newo newo = lastRight } } newc, err := cfio.newFileChunk(newo) if err != nil { return err } if err := writeToChunk(&newc, NewChunk, maxlen); err != nil { return err } cs = append(cs, newc) if err := cfio.caio.Write(cs); err != nil { return fmt.Errorf("Failed to write updated cs array: %v", err) } } return nil }