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

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

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

Powered by Google App Engine
This is Rietveld 408576698