...

Source file src/github.com/sassoftware/relic/lib/comdoc/sectors.go

Documentation: github.com/sassoftware/relic/lib/comdoc

     1  //
     2  // Copyright (c) SAS Institute Inc.
     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 comdoc
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/binary"
    22  	"errors"
    23  )
    24  
    25  // Convert a sector ID to an absolute file position
    26  func (r *ComDoc) sectorToOffset(sector SecID) int64 {
    27  	if sector < 0 {
    28  		return -1
    29  	}
    30  	return r.FirstSector + int64(sector)*int64(r.SectorSize)
    31  }
    32  
    33  // Read the specified sector
    34  func (r *ComDoc) readSector(sector SecID, buf []byte) error {
    35  	_, err := r.File.ReadAt(buf, r.sectorToOffset(sector))
    36  	return err
    37  }
    38  
    39  // Read the specified sector into a binary structure. It must be exactly 1
    40  // sector in size already.
    41  func (r *ComDoc) readSectorStruct(sector SecID, v interface{}) error {
    42  	if err := r.readSector(sector, r.sectorBuf); err != nil {
    43  		return err
    44  	}
    45  	return binary.Read(bytes.NewReader(r.sectorBuf), binary.LittleEndian, v)
    46  }
    47  
    48  // Write to a specified sector. Content will be padded with zeroes if it is
    49  // less than a full sector in length.
    50  func (r *ComDoc) writeSector(sector SecID, content []byte) error {
    51  	if len(content) > r.SectorSize {
    52  		panic("excessive write")
    53  	} else if len(content) < r.SectorSize {
    54  		buf := r.sectorBuf
    55  		copy(buf, content)
    56  		for i := len(content); i < r.SectorSize; i++ {
    57  			buf[i] = 0
    58  		}
    59  		content = buf[:r.SectorSize]
    60  	}
    61  	_, err := r.writer.WriteAt(content, r.sectorToOffset(sector))
    62  	return err
    63  }
    64  
    65  // Mark a chain of sectors as free
    66  func freeSectors(sat []SecID, sector SecID) {
    67  	for {
    68  		nextSector := sat[sector]
    69  		sat[sector] = SecIDFree
    70  		if nextSector < 0 {
    71  			break
    72  		}
    73  		sector = nextSector
    74  	}
    75  }
    76  
    77  // Return a list of "count" free sectors or short sectors, extending the table if needed
    78  func (r *ComDoc) makeFreeSectors(count int, short bool) []SecID {
    79  	if count <= 0 {
    80  		return nil
    81  	}
    82  	freeList := make([]SecID, 0, count)
    83  	var sat []SecID
    84  	if short {
    85  		sat = r.SSAT
    86  	} else {
    87  		sat = r.SAT
    88  	}
    89  	// scan for existing free sectors
    90  	for i, j := range sat {
    91  		if j != SecIDFree {
    92  			continue
    93  		}
    94  		freeList = append(freeList, SecID(i))
    95  		count--
    96  		if count == 0 {
    97  			return freeList
    98  		}
    99  	}
   100  	// extend the sector table
   101  	sectorsPerBlock := r.SectorSize / 4
   102  	needBlocks := (count + sectorsPerBlock - 1) / sectorsPerBlock
   103  	oldCount := len(sat)
   104  	newSAT := append(sat, make([]SecID, needBlocks*sectorsPerBlock)...)
   105  	for i := oldCount; i < len(newSAT); i++ {
   106  		newSAT[i] = SecIDFree
   107  		if count > 0 {
   108  			freeList = append(freeList, SecID(i))
   109  			count--
   110  		}
   111  	}
   112  	if short {
   113  		r.SSAT = newSAT
   114  	} else {
   115  		r.SAT = newSAT
   116  	}
   117  	return freeList
   118  }
   119  
   120  // Read the sector allocation table.
   121  //
   122  // Each index within the table corresponds to a sector within the file itself.
   123  // The value held at that index in the SAT either points to the ID of the
   124  // sector holding the next chunk of data for that stream, or -2 to indicate
   125  // there are no more sectors.
   126  func (r *ComDoc) readSAT() error {
   127  	count := r.SectorSize / 4
   128  	sat := make([]SecID, count*int(r.Header.SATSectors))
   129  	position := 0
   130  	for _, sector := range r.MSAT {
   131  		if sector < 0 {
   132  			continue
   133  		}
   134  		if position >= len(sat) {
   135  			return errors.New("msat has more sectors than indicated")
   136  		}
   137  		if err := r.readSectorStruct(sector, sat[position:position+count]); err != nil {
   138  			return err
   139  		}
   140  		position += count
   141  	}
   142  	r.SAT = sat
   143  	return nil
   144  }
   145  
   146  // Write the new sector allocation table to the listed sector IDs
   147  func (r *ComDoc) writeSAT(freeList []SecID) error {
   148  	satPerSector := r.SectorSize / 4
   149  	buf := bytes.NewBuffer(r.sectorBuf)
   150  	for i, sector := range freeList {
   151  		j := i * satPerSector
   152  		buf.Reset()
   153  		binary.Write(buf, binary.LittleEndian, r.SAT[j:j+satPerSector])
   154  		if err := r.writeSector(sector, buf.Bytes()); err != nil {
   155  			return err
   156  		}
   157  	}
   158  	return nil
   159  }
   160  

View as plain text