github.com/jlowellwofford/u-root@v1.0.0/xcmds/archive/vtoc.go (about)

     1  // Copyright 2013 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  	"os"
    14  	"path/filepath"
    15  	"syscall"
    16  )
    17  
    18  func loadVTOC(name string) (*os.File, []file, error) {
    19  	var l int64
    20  	f, err := os.Open(name)
    21  	if err != nil {
    22  		return nil, nil, err
    23  	}
    24  	r := io.LimitReader(f, 8)
    25  	_, err = fmt.Fscanf(r, "%x", &l)
    26  	if err != nil {
    27  		return nil, nil, fmt.Errorf("%s: can't scan vtoc length: %v", name, err)
    28  	}
    29  
    30  	r = io.LimitReader(f, l)
    31  	dec := json.NewDecoder(r)
    32  
    33  	var vtoc []file
    34  	if err := dec.Decode(&vtoc); err != nil {
    35  		return nil, nil, fmt.Errorf("%s: can't decode: %v", name, err)
    36  	}
    37  	return f, vtoc, nil
    38  }
    39  
    40  func buildVTOC(dirs []string) ([]*file, error) {
    41  	var vtoc []*file
    42  	for _, v := range dirs {
    43  		debug("Process %v", v)
    44  		err := filepath.Walk(v, func(name string, fi os.FileInfo, err error) error {
    45  			if err != nil {
    46  				return err
    47  			}
    48  			debug("visit %v", name)
    49  			var s syscall.Stat_t
    50  			if err := syscall.Lstat(name, &s); err != nil {
    51  				return fmt.Errorf("%s: %v", name, err)
    52  			}
    53  			f := &file{
    54  				Name:    name,
    55  				Mode:    fi.Mode(),
    56  				ModTime: fi.ModTime(),
    57  				IsDir:   fi.IsDir(),
    58  				Uid:     int(s.Uid),
    59  				Gid:     int(s.Gid),
    60  			}
    61  			switch f.Mode.String()[0] {
    62  			case '-':
    63  				f.Size = fi.Size()
    64  			case 'L':
    65  				f.Link, err = os.Readlink(name)
    66  			case 'D':
    67  				// On FreeBSD Rdev type is uint32
    68  				f.Dev = uint64(s.Rdev)
    69  			}
    70  			vtoc = append(vtoc, f)
    71  			return err
    72  		})
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  	}
    77  
    78  	return vtoc, nil
    79  }
    80  
    81  func encodeVTOC(vtoc []*file) (int64, error) {
    82  	return -1, errors.New("not yet")
    83  }
    84  
    85  func writeVTOC(f io.Writer, vtoc []*file) (int, error) {
    86  	var outvtoc = make([]*file, len(vtoc))
    87  	// Do a little cleanup
    88  	for i := range vtoc {
    89  		// The path names may be absolute but they will also have been cleaned.
    90  		// If the first char is /, it won't be.
    91  		// N.B. This assumes Unix-style file names. But I don't care about Windows.
    92  		v := *vtoc[i]
    93  		outvtoc[i] = &v
    94  		if outvtoc[i].Name[0] == '/' {
    95  			outvtoc[i].Name = outvtoc[i].Name[1:]
    96  		}
    97  	}
    98  
    99  	var v bytes.Buffer
   100  	enc := json.NewEncoder(&v)
   101  	if err := enc.Encode(outvtoc); err != nil {
   102  		return -1, fmt.Errorf("Encoding files: %v", err)
   103  	}
   104  
   105  	if _, err := fmt.Fprintf(f, "%07x\n", v.Len()); err != nil {
   106  		return -1, err
   107  	}
   108  	debug("vtoc size is %d", v.Len())
   109  	return f.Write(v.Bytes())
   110  }
   111  
   112  func NewVTOCEncoder(opts ...VTOCOpt) error {
   113  	var v vtoc
   114  
   115  	for _, o := range opts {
   116  		if err := o(&v); err != nil {
   117  			return err
   118  		}
   119  	}
   120  	return nil
   121  }