~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to src/pkg/os/file_windows.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
        "sync"
11
11
        "syscall"
12
12
        "unicode/utf16"
 
13
        "unicode/utf8"
 
14
        "unsafe"
13
15
)
14
16
 
15
17
// File represents an open file descriptor.
25
27
        fd      syscall.Handle
26
28
        name    string
27
29
        dirinfo *dirInfo   // nil unless directory being read
28
 
        nepipe  int        // number of consecutive EPIPE in Write
29
30
        l       sync.Mutex // used to implement windows pread/pwrite
 
31
 
 
32
        // only for console io
 
33
        isConsole bool
 
34
        lastbits  []byte // first few bytes of the last incomplete rune in last write
 
35
        readbuf   []rune // input console buffer
30
36
}
31
37
 
32
38
// Fd returns the Windows handle referencing the open file.
37
43
        return uintptr(file.fd)
38
44
}
39
45
 
 
46
// newFile returns a new File with the given file handle and name.
 
47
// Unlike NewFile, it does not check that h is syscall.InvalidHandle.
 
48
func newFile(h syscall.Handle, name string) *File {
 
49
        f := &File{&file{fd: h, name: name}}
 
50
        var m uint32
 
51
        if syscall.GetConsoleMode(f.fd, &m) == nil {
 
52
                f.isConsole = true
 
53
        }
 
54
        runtime.SetFinalizer(f.file, (*file).close)
 
55
        return f
 
56
}
 
57
 
40
58
// NewFile returns a new File with the given file descriptor and name.
41
59
func NewFile(fd uintptr, name string) *File {
42
60
        h := syscall.Handle(fd)
43
61
        if h == syscall.InvalidHandle {
44
62
                return nil
45
63
        }
46
 
        f := &File{&file{fd: h, name: name}}
47
 
        runtime.SetFinalizer(f.file, (*file).close)
48
 
        return f
 
64
        return newFile(h, name)
49
65
}
50
66
 
51
67
// Auxiliary information if the File describes a directory
53
69
        data     syscall.Win32finddata
54
70
        needdata bool
55
71
        path     string
 
72
        isempty  bool // set if FindFirstFile returns ERROR_FILE_NOT_FOUND
 
73
}
 
74
 
 
75
func epipecheck(file *File, e error) {
56
76
}
57
77
 
58
78
const DevNull = "NUL"
62
82
func openFile(name string, flag int, perm FileMode) (file *File, err error) {
63
83
        r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
64
84
        if e != nil {
65
 
                return nil, &PathError{"open", name, e}
66
 
        }
67
 
 
68
 
        // There's a race here with fork/exec, which we are
69
 
        // content to live with.  See ../syscall/exec.go
70
 
        if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
71
 
                syscall.CloseOnExec(r)
72
 
        }
73
 
 
 
85
                return nil, e
 
86
        }
74
87
        return NewFile(uintptr(r), name), nil
75
88
}
76
89
 
77
90
func openDir(name string) (file *File, err error) {
 
91
        maskp, e := syscall.UTF16PtrFromString(name + `\*`)
 
92
        if e != nil {
 
93
                return nil, e
 
94
        }
78
95
        d := new(dirInfo)
79
 
        r, e := syscall.FindFirstFile(syscall.StringToUTF16Ptr(name+`\*`), &d.data)
 
96
        r, e := syscall.FindFirstFile(maskp, &d.data)
80
97
        if e != nil {
81
 
                return nil, &PathError{"open", name, e}
 
98
                // FindFirstFile returns ERROR_FILE_NOT_FOUND when
 
99
                // no matching files can be found. Then, if directory
 
100
                // exists, we should proceed.
 
101
                if e != syscall.ERROR_FILE_NOT_FOUND {
 
102
                        return nil, e
 
103
                }
 
104
                var fa syscall.Win32FileAttributeData
 
105
                namep, e := syscall.UTF16PtrFromString(name)
 
106
                if e != nil {
 
107
                        return nil, e
 
108
                }
 
109
                e = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa)))
 
110
                if e != nil {
 
111
                        return nil, e
 
112
                }
 
113
                if fa.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY == 0 {
 
114
                        return nil, e
 
115
                }
 
116
                d.isempty = true
82
117
        }
83
118
        d.path = name
84
119
        if !isAbs(d.path) {
85
120
                cwd, _ := Getwd()
86
121
                d.path = cwd + `\` + d.path
87
122
        }
88
 
        f := NewFile(uintptr(r), name)
 
123
        f := newFile(r, name)
89
124
        f.dirinfo = d
90
125
        return f, nil
91
126
}
112
147
        if e == nil {
113
148
                return r, nil
114
149
        }
115
 
        return nil, e
 
150
        return nil, &PathError{"open", name, e}
116
151
}
117
152
 
118
153
// Close closes the File, rendering it unusable for I/O.
122
157
}
123
158
 
124
159
func (file *file) close() error {
125
 
        if file == nil || file.fd == syscall.InvalidHandle {
 
160
        if file == nil {
 
161
                return syscall.EINVAL
 
162
        }
 
163
        if file.isdir() && file.dirinfo.isempty {
 
164
                // "special" empty directories
 
165
                return nil
 
166
        }
 
167
        if file.fd == syscall.InvalidHandle {
126
168
                return syscall.EINVAL
127
169
        }
128
170
        var e error
143
185
}
144
186
 
145
187
func (file *File) readdir(n int) (fi []FileInfo, err error) {
146
 
        if file == nil || file.fd == syscall.InvalidHandle {
 
188
        if file == nil {
147
189
                return nil, syscall.EINVAL
148
190
        }
149
191
        if !file.isdir() {
150
192
                return nil, &PathError{"Readdir", file.name, syscall.ENOTDIR}
151
193
        }
 
194
        if !file.dirinfo.isempty && file.fd == syscall.InvalidHandle {
 
195
                return nil, syscall.EINVAL
 
196
        }
152
197
        wantAll := n <= 0
153
198
        size := n
154
199
        if wantAll {
157
202
        }
158
203
        fi = make([]FileInfo, 0, size) // Empty with room to grow.
159
204
        d := &file.dirinfo.data
160
 
        for n != 0 {
 
205
        for n != 0 && !file.dirinfo.isempty {
161
206
                if file.dirinfo.needdata {
162
207
                        e := syscall.FindNextFile(syscall.Handle(file.fd), d)
163
208
                        if e != nil {
178
223
                        continue
179
224
                }
180
225
                f := &fileStat{
181
 
                        name:    name,
182
 
                        size:    mkSize(d.FileSizeHigh, d.FileSizeLow),
183
 
                        modTime: mkModTime(d.LastWriteTime),
184
 
                        mode:    mkMode(d.FileAttributes),
185
 
                        sys:     mkSys(file.dirinfo.path+`\`+name, d.LastAccessTime, d.CreationTime),
 
226
                        name: name,
 
227
                        sys: syscall.Win32FileAttributeData{
 
228
                                FileAttributes: d.FileAttributes,
 
229
                                CreationTime:   d.CreationTime,
 
230
                                LastAccessTime: d.LastAccessTime,
 
231
                                LastWriteTime:  d.LastWriteTime,
 
232
                                FileSizeHigh:   d.FileSizeHigh,
 
233
                                FileSizeLow:    d.FileSizeLow,
 
234
                        },
 
235
                        path: file.dirinfo.path + `\` + name,
186
236
                }
187
237
                n--
188
238
                fi = append(fi, f)
193
243
        return fi, nil
194
244
}
195
245
 
 
246
// readConsole reads utf16 characters from console File,
 
247
// encodes them into utf8 and stores them in buffer b.
 
248
// It returns the number of utf8 bytes read and an error, if any.
 
249
func (f *File) readConsole(b []byte) (n int, err error) {
 
250
        if len(b) == 0 {
 
251
                return 0, nil
 
252
        }
 
253
        if len(f.readbuf) == 0 {
 
254
                // get more input data from os
 
255
                wchars := make([]uint16, len(b))
 
256
                var p *uint16
 
257
                if len(b) > 0 {
 
258
                        p = &wchars[0]
 
259
                }
 
260
                var nw uint32
 
261
                err := syscall.ReadConsole(f.fd, p, uint32(len(wchars)), &nw, nil)
 
262
                if err != nil {
 
263
                        return 0, err
 
264
                }
 
265
                f.readbuf = utf16.Decode(wchars[:nw])
 
266
        }
 
267
        for i, r := range f.readbuf {
 
268
                if utf8.RuneLen(r) > len(b) {
 
269
                        f.readbuf = f.readbuf[i:]
 
270
                        return n, nil
 
271
                }
 
272
                nr := utf8.EncodeRune(b, r)
 
273
                b = b[nr:]
 
274
                n += nr
 
275
        }
 
276
        f.readbuf = nil
 
277
        return n, nil
 
278
}
 
279
 
196
280
// read reads up to len(b) bytes from the File.
197
281
// It returns the number of bytes read and an error, if any.
198
282
func (f *File) read(b []byte) (n int, err error) {
199
283
        f.l.Lock()
200
284
        defer f.l.Unlock()
 
285
        if f.isConsole {
 
286
                return f.readConsole(b)
 
287
        }
201
288
        return syscall.Read(f.fd, b)
202
289
}
203
290
 
224
311
        return int(done), nil
225
312
}
226
313
 
 
314
// writeConsole writes len(b) bytes to the console File.
 
315
// It returns the number of bytes written and an error, if any.
 
316
func (f *File) writeConsole(b []byte) (n int, err error) {
 
317
        n = len(b)
 
318
        runes := make([]rune, 0, 256)
 
319
        if len(f.lastbits) > 0 {
 
320
                b = append(f.lastbits, b...)
 
321
                f.lastbits = nil
 
322
 
 
323
        }
 
324
        for len(b) >= utf8.UTFMax || utf8.FullRune(b) {
 
325
                r, l := utf8.DecodeRune(b)
 
326
                runes = append(runes, r)
 
327
                b = b[l:]
 
328
        }
 
329
        if len(b) > 0 {
 
330
                f.lastbits = make([]byte, len(b))
 
331
                copy(f.lastbits, b)
 
332
        }
 
333
        // syscall.WriteConsole seems to fail, if given large buffer.
 
334
        // So limit the buffer to 16000 characters. This number was
 
335
        // discovered by experimenting with syscall.WriteConsole.
 
336
        const maxWrite = 16000
 
337
        for len(runes) > 0 {
 
338
                m := len(runes)
 
339
                if m > maxWrite {
 
340
                        m = maxWrite
 
341
                }
 
342
                chunk := runes[:m]
 
343
                runes = runes[m:]
 
344
                uint16s := utf16.Encode(chunk)
 
345
                for len(uint16s) > 0 {
 
346
                        var written uint32
 
347
                        err = syscall.WriteConsole(f.fd, &uint16s[0], uint32(len(uint16s)), &written, nil)
 
348
                        if err != nil {
 
349
                                return 0, nil
 
350
                        }
 
351
                        uint16s = uint16s[written:]
 
352
                }
 
353
        }
 
354
        return n, nil
 
355
}
 
356
 
227
357
// write writes len(b) bytes to the File.
228
358
// It returns the number of bytes written and an error, if any.
229
359
func (f *File) write(b []byte) (n int, err error) {
230
360
        f.l.Lock()
231
361
        defer f.l.Unlock()
 
362
        if f.isConsole {
 
363
                return f.writeConsole(b)
 
364
        }
232
365
        return syscall.Write(f.fd, b)
233
366
}
234
367
 
282
415
// Remove removes the named file or directory.
283
416
// If there is an error, it will be of type *PathError.
284
417
func Remove(name string) error {
285
 
        p := &syscall.StringToUTF16(name)[0]
 
418
        p, e := syscall.UTF16PtrFromString(name)
 
419
        if e != nil {
 
420
                return &PathError{"remove", name, e}
 
421
        }
286
422
 
287
423
        // Go file interface forces us to know whether
288
424
        // name is a file or directory. Try both.
289
 
        e := syscall.DeleteFile(p)
 
425
        e = syscall.DeleteFile(p)
290
426
        if e == nil {
291
427
                return nil
292
428
        }