Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: common/archive/ar/writer.go

Issue 2014243002: WIP: Archive command which is much faster (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: Fixes. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 // Write an ar archive file with BSD style filenames.
6
7 package ar
8
9 import (
10 "errors"
11 "fmt"
12 "io"
13 "os"
14 )
15
16 const DEFAULT_MODTIME = 1447140471
17 const DEFAULT_USER = 1000
18 const DEFAULT_GROUP = 1000
19 const DEFAULT_MODE = 0100640 // 100640 -- Octal
20
21 type WriterStage uint
22
23 const (
24 WRITE_HEADER WriterStage = iota
25 WRITE_BODY
26 WRITE_CLOSED
27 )
28
29 type Writer struct {
30 w io.Writer
31 stage WriterStage
32
33 bytesrequired int64
34 needspadding bool
35 }
36
37 func NewWriter(w io.Writer) *Writer {
38 io.WriteString(w, "!<arch>\n")
39 return &Writer{w: w, stage: WRITE_HEADER, bytesrequired: 0, needspadding : false}
40 }
41
42 func (aw *Writer) Close() error {
43 switch aw.stage {
44 case WRITE_HEADER:
45 // Good
46 case WRITE_BODY:
47 return errors.New("Usage error, writing a file.")
48 case WRITE_CLOSED:
49 return errors.New("Usage error, archive already closed.")
50 default:
51 panic(fmt.Sprintf("Unknown writer mode: %d", aw.stage))
52 }
53 //aw.w.Close()
54 aw.stage = WRITE_CLOSED
55 return nil
56 }
57
58 func (aw *Writer) wroteBytes(numbytes int64) error {
59 if numbytes > aw.bytesrequired {
60 panic(fmt.Sprintf("To much data written! Needed %d, got %d", aw. bytesrequired, numbytes))
61 }
62
63 aw.bytesrequired -= numbytes
64 if aw.bytesrequired != 0 {
65 return nil
66 }
67
68 // Padding to 16bit boundary
69 if aw.needspadding {
70 io.WriteString(aw.w, "\n")
71 aw.needspadding = false
72 }
73 aw.stage = WRITE_HEADER
74 return nil
75 }
76
77 // Check you can write bytes to the ar at this moment.
78 func (aw *Writer) checkWrite() error {
79 switch aw.stage {
80 case WRITE_HEADER:
81 return errors.New("Usage error, need to write header first.")
82 // Good
83 case WRITE_BODY:
84 return nil
85 case WRITE_CLOSED:
86 return errors.New("Usage error, archive closed.")
87 default:
88 panic(fmt.Sprintf("Unknown writer mode: %d", aw.stage))
89 }
90 }
91
92 // Check we have finished writing bytes
93 func (aw *Writer) checkFinished() {
94 if aw.bytesrequired != 0 {
95 panic(fmt.Sprintf("Didn't write enough bytes %d still needed, ar chive corrupted!", aw.bytesrequired))
96 }
97 }
98
99 func (aw *Writer) writePartial(data []byte) error {
100 err := aw.checkWrite()
101 if err != nil {
102 return err
103 }
104
105 datalen := int64(len(data))
106 if datalen > aw.bytesrequired {
107 return errors.New(fmt.Sprintf("To much data! Needed %d, got %d", aw.bytesrequired, datalen))
108 }
109
110 aw.w.Write(data)
111 aw.wroteBytes(datalen)
112 return nil
113 }
114
115 func (aw *Writer) WriteReader(data io.Reader) error {
116 err := aw.checkWrite()
117 if err != nil {
118 return err
119 }
120
121 count, err := io.Copy(aw.w, data)
122 if err != nil {
123 panic(fmt.Sprintf("err while copying (%s), archive is probably c orrupted!", err))
124 }
125 aw.wroteBytes(count)
126 aw.checkFinished()
127
128 return nil
129 }
130
131 func (aw *Writer) WriteBytes(data []byte) error {
132 err := aw.checkWrite()
133 if err != nil {
134 return err
135 }
136
137 datalen := int64(len(data))
138 if datalen != aw.bytesrequired {
139 return errors.New(fmt.Sprintf("Wrong amount of data! Needed %d, got %d", aw.bytesrequired, datalen))
140 }
141
142 aw.writePartial(data)
143 aw.checkFinished()
144 return nil
145 }
146
147 func (aw *Writer) writeHeaderBytes(name string, size int64, modtime uint64, owne rid uint, groupid uint, filemod uint) error {
148 switch aw.stage {
149 case WRITE_HEADER:
150 // Good
151 case WRITE_BODY:
152 return errors.New("Usage error, already writing a file.")
153 case WRITE_CLOSED:
154 return errors.New("Usage error, archive closed.")
155 default:
156 panic(fmt.Sprintf("Unknown writer mode: %d", aw.stage))
157 }
158
159 // File name length prefixed with '#1/' (BSD variant), 16 bytes
160 fmt.Fprintf(aw.w, "#1/%-13d", len(name))
161
162 // Modtime, 12 bytes
163 fmt.Fprintf(aw.w, "%-12d", modtime)
164
165 // Owner ID, 6 bytes
166 fmt.Fprintf(aw.w, "%-6d", ownerid)
167
168 // Group ID, 6 bytes
169 fmt.Fprintf(aw.w, "%-6d", groupid)
170
171 // File mode, 8 bytes
172 fmt.Fprintf(aw.w, "%-8o", filemod)
173
174 // In BSD variant, file size includes the filename length
175 aw.bytesrequired = int64(len(name)) + size
176
177 // File size, 10 bytes
178 fmt.Fprintf(aw.w, "%-10d", aw.bytesrequired)
179
180 // File magic, 2 bytes
181 io.WriteString(aw.w, "\x60\n")
182
183 aw.stage = WRITE_BODY
184 aw.needspadding = (aw.bytesrequired%2 != 0)
185
186 // Filename - BSD variant
187 return aw.writePartial([]byte(name))
188 }
189
190 func (aw *Writer) WriteHeaderDefault(name string, size int64) error {
191 return aw.writeHeaderBytes(name, size, 1447140471, DEFAULT_USER, DEFAULT _GROUP, DEFAULT_MODE)
192 }
193
194 func (aw *Writer) WriteHeader(stat os.FileInfo) error {
195 if stat.IsDir() {
196 return errors.New("Only work with files, not directories.")
197 }
198
199 mode := stat.Mode()
200 if mode&os.ModeSymlink == os.ModeSymlink {
201 return errors.New("Only work with files, not symlinks.")
202 }
203
204 /* FIXME: Should we also exclude other "special" files?
205 if (stat.Mode().ModeType != 0) {
206 return &argError{stat, "Only work with plain files."}
207 }
208 */
209
210 // FIXME: Where do we get user/group from - they don't appear to be in G o's Mode() object?
211 return aw.writeHeaderBytes(stat.Name(), stat.Size(), uint64(stat.ModTime ().Unix()), DEFAULT_USER, DEFAULT_GROUP, uint(mode&os.ModePerm))
212 }
213
214 func (aw *Writer) Add(name string, data []byte) error {
215 err := aw.WriteHeaderDefault(name, int64(len(data)))
216 if err != nil {
217 return err
218 }
219
220 return aw.WriteBytes(data)
221 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698