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 }