Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 1 | // Copyright 2009 The Go 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 | |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 5 | package os |
| 6 | |
| 7 | import ( |
Russ Cox | 08a073a | 2011-11-01 21:49:08 -0400 | [diff] [blame] | 8 | "io" |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 9 | "runtime" |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 10 | "sync" |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 11 | "syscall" |
Alex Brainman | 0d37998 | 2011-11-15 12:48:22 -0500 | [diff] [blame] | 12 | "unicode/utf16" |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 13 | ) |
| 14 | |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 15 | // File represents an open file descriptor. |
| 16 | type File struct { |
Russ Cox | d03611f | 2011-11-15 12:20:59 -0500 | [diff] [blame] | 17 | *file |
| 18 | } |
| 19 | |
| 20 | // file is the real representation of *File. |
| 21 | // The extra level of indirection ensures that no clients of os |
| 22 | // can overwrite this data, which could cause the finalizer |
| 23 | // to close the wrong file descriptor. |
| 24 | type file struct { |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 25 | fd syscall.Handle |
| 26 | name string |
| 27 | dirinfo *dirInfo // nil unless directory being read |
| 28 | nepipe int // number of consecutive EPIPE in Write |
| 29 | l sync.Mutex // used to implement windows pread/pwrite |
| 30 | } |
| 31 | |
| 32 | // Fd returns the Windows handle referencing the open file. |
| 33 | func (file *File) Fd() syscall.Handle { |
| 34 | if file == nil { |
| 35 | return syscall.InvalidHandle |
| 36 | } |
| 37 | return file.fd |
| 38 | } |
| 39 | |
| 40 | // NewFile returns a new File with the given file descriptor and name. |
| 41 | func NewFile(fd syscall.Handle, name string) *File { |
Wei Guangjing | 4ea5d62 | 2012-02-02 10:17:52 +1100 | [diff] [blame] | 42 | if fd == syscall.InvalidHandle { |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 43 | return nil |
| 44 | } |
Russ Cox | d03611f | 2011-11-15 12:20:59 -0500 | [diff] [blame] | 45 | f := &File{&file{fd: fd, name: name}} |
| 46 | runtime.SetFinalizer(f.file, (*file).close) |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 47 | return f |
| 48 | } |
| 49 | |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 50 | // Auxiliary information if the File describes a directory |
| 51 | type dirInfo struct { |
Alex Brainman | 37f390a | 2011-09-06 09:59:08 +1000 | [diff] [blame] | 52 | data syscall.Win32finddata |
| 53 | needdata bool |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 54 | } |
| 55 | |
Peter Mundy | 12befd0 | 2010-08-03 13:03:50 -0700 | [diff] [blame] | 56 | const DevNull = "NUL" |
| 57 | |
Russ Cox | 8fe7701 | 2012-01-10 20:26:11 -0800 | [diff] [blame] | 58 | func (f *file) isdir() bool { return f != nil && f.dirinfo != nil } |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 59 | |
Brad Fitzpatrick | 6454a3e | 2012-01-19 15:45:18 -0800 | [diff] [blame] | 60 | func openFile(name string, flag int, perm FileMode) (file *File, err error) { |
| 61 | r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 62 | if e != nil { |
| 63 | return nil, &PathError{"open", name, e} |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 64 | } |
| 65 | |
| 66 | // There's a race here with fork/exec, which we are |
| 67 | // content to live with. See ../syscall/exec.go |
| 68 | if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported |
| 69 | syscall.CloseOnExec(r) |
| 70 | } |
| 71 | |
| 72 | return NewFile(r, name), nil |
| 73 | } |
| 74 | |
Russ Cox | 08a073a | 2011-11-01 21:49:08 -0400 | [diff] [blame] | 75 | func openDir(name string) (file *File, err error) { |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 76 | d := new(dirInfo) |
Alex Brainman | 37f390a | 2011-09-06 09:59:08 +1000 | [diff] [blame] | 77 | r, e := syscall.FindFirstFile(syscall.StringToUTF16Ptr(name+`\*`), &d.data) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 78 | if e != nil { |
| 79 | return nil, &PathError{"open", name, e} |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 80 | } |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 81 | f := NewFile(r, name) |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 82 | f.dirinfo = d |
| 83 | return f, nil |
| 84 | } |
| 85 | |
Rob Pike | 8a90fd3 | 2011-04-04 23:42:14 -0700 | [diff] [blame] | 86 | // OpenFile is the generalized open call; most users will use Open |
| 87 | // or Create instead. It opens the named file with specified flag |
| 88 | // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful, |
| 89 | // methods on the returned File can be used for I/O. |
Rob Pike | be0f6fe | 2012-02-09 16:55:36 +1100 | [diff] [blame] | 90 | // If there is an error, it will be of type *PathError. |
Brad Fitzpatrick | 6454a3e | 2012-01-19 15:45:18 -0800 | [diff] [blame] | 91 | func OpenFile(name string, flag int, perm FileMode) (file *File, err error) { |
Alex Brainman | e38a105 | 2011-11-26 11:01:49 +1100 | [diff] [blame] | 92 | if name == "" { |
| 93 | return nil, &PathError{"open", name, syscall.ENOENT} |
| 94 | } |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 95 | // TODO(brainman): not sure about my logic of assuming it is dir first, then fall back to file |
| 96 | r, e := openDir(name) |
| 97 | if e == nil { |
Alex Brainman | 17fe247 | 2010-10-04 17:31:49 +1100 | [diff] [blame] | 98 | if flag&O_WRONLY != 0 || flag&O_RDWR != 0 { |
| 99 | r.Close() |
| 100 | return nil, &PathError{"open", name, EISDIR} |
| 101 | } |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 102 | return r, nil |
| 103 | } |
Alex Brainman | 0352659 | 2010-04-13 22:30:41 -0700 | [diff] [blame] | 104 | r, e = openFile(name, flag, perm) |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 105 | if e == nil { |
| 106 | return r, nil |
| 107 | } |
| 108 | return nil, e |
| 109 | } |
| 110 | |
| 111 | // Close closes the File, rendering it unusable for I/O. |
Russ Cox | 08a073a | 2011-11-01 21:49:08 -0400 | [diff] [blame] | 112 | // It returns an error, if any. |
| 113 | func (file *File) Close() error { |
Russ Cox | d03611f | 2011-11-15 12:20:59 -0500 | [diff] [blame] | 114 | return file.file.close() |
| 115 | } |
| 116 | |
| 117 | func (file *file) close() error { |
Wei Guangjing | 4ea5d62 | 2012-02-02 10:17:52 +1100 | [diff] [blame] | 118 | if file == nil || file.fd == syscall.InvalidHandle { |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 119 | return EINVAL |
| 120 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 121 | var e error |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 122 | if file.isdir() { |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 123 | e = syscall.FindClose(syscall.Handle(file.fd)) |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 124 | } else { |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 125 | e = syscall.CloseHandle(syscall.Handle(file.fd)) |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 126 | } |
Russ Cox | 08a073a | 2011-11-01 21:49:08 -0400 | [diff] [blame] | 127 | var err error |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 128 | if e != nil { |
| 129 | err = &PathError{"close", file.name, e} |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 130 | } |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 131 | file.fd = syscall.InvalidHandle // so it can't be closed again |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 132 | |
| 133 | // no need for a finalizer anymore |
| 134 | runtime.SetFinalizer(file, nil) |
| 135 | return err |
| 136 | } |
| 137 | |
Alex Brainman | 994e064 | 2012-01-17 16:51:54 +1100 | [diff] [blame] | 138 | func (file *File) readdir(n int) (fi []FileInfo, err error) { |
Wei Guangjing | 4ea5d62 | 2012-02-02 10:17:52 +1100 | [diff] [blame] | 139 | if file == nil || file.fd == syscall.InvalidHandle { |
Peter Mundy | bfb1276 | 2010-09-23 22:06:59 -0400 | [diff] [blame] | 140 | return nil, EINVAL |
| 141 | } |
| 142 | if !file.isdir() { |
| 143 | return nil, &PathError{"Readdir", file.name, ENOTDIR} |
| 144 | } |
Alex Brainman | 505f0bb | 2011-05-29 11:59:35 +1000 | [diff] [blame] | 145 | wantAll := n <= 0 |
Brad Fitzpatrick | 4da5cd4 | 2011-05-16 09:26:16 -0700 | [diff] [blame] | 146 | size := n |
Alex Brainman | 505f0bb | 2011-05-29 11:59:35 +1000 | [diff] [blame] | 147 | if wantAll { |
| 148 | n = -1 |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 149 | size = 100 |
| 150 | } |
| 151 | fi = make([]FileInfo, 0, size) // Empty with room to grow. |
Alex Brainman | 37f390a | 2011-09-06 09:59:08 +1000 | [diff] [blame] | 152 | d := &file.dirinfo.data |
Brad Fitzpatrick | 4da5cd4 | 2011-05-16 09:26:16 -0700 | [diff] [blame] | 153 | for n != 0 { |
Alex Brainman | 37f390a | 2011-09-06 09:59:08 +1000 | [diff] [blame] | 154 | if file.dirinfo.needdata { |
| 155 | e := syscall.FindNextFile(syscall.Handle(file.fd), d) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 156 | if e != nil { |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 157 | if e == syscall.ERROR_NO_MORE_FILES { |
| 158 | break |
| 159 | } else { |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 160 | err = &PathError{"FindNextFile", file.name, e} |
Brad Fitzpatrick | 4da5cd4 | 2011-05-16 09:26:16 -0700 | [diff] [blame] | 161 | if !wantAll { |
| 162 | fi = nil |
| 163 | } |
| 164 | return |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 165 | } |
| 166 | } |
| 167 | } |
Alex Brainman | 37f390a | 2011-09-06 09:59:08 +1000 | [diff] [blame] | 168 | file.dirinfo.needdata = true |
Russ Cox | 8dce57e | 2011-11-30 12:04:16 -0500 | [diff] [blame] | 169 | name := string(syscall.UTF16ToString(d.FileName[0:])) |
| 170 | if name == "." || name == ".." { // Useless names |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 171 | continue |
| 172 | } |
Russ Cox | 8dce57e | 2011-11-30 12:04:16 -0500 | [diff] [blame] | 173 | f := toFileInfo(name, d.FileAttributes, d.FileSizeHigh, d.FileSizeLow, d.CreationTime, d.LastAccessTime, d.LastWriteTime) |
Brad Fitzpatrick | 4da5cd4 | 2011-05-16 09:26:16 -0700 | [diff] [blame] | 174 | n-- |
Russ Cox | 69c4e93 | 2010-10-27 19:47:23 -0700 | [diff] [blame] | 175 | fi = append(fi, f) |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 176 | } |
Brad Fitzpatrick | 4da5cd4 | 2011-05-16 09:26:16 -0700 | [diff] [blame] | 177 | if !wantAll && len(fi) == 0 { |
Russ Cox | 08a073a | 2011-11-01 21:49:08 -0400 | [diff] [blame] | 178 | return fi, io.EOF |
Brad Fitzpatrick | 4da5cd4 | 2011-05-16 09:26:16 -0700 | [diff] [blame] | 179 | } |
Alex Brainman | b07e4d9 | 2010-04-13 16:30:11 -0700 | [diff] [blame] | 180 | return fi, nil |
| 181 | } |
Alex Brainman | fb6b391 | 2010-04-26 23:17:14 -0700 | [diff] [blame] | 182 | |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 183 | // read reads up to len(b) bytes from the File. |
| 184 | // It returns the number of bytes read and an error, if any. |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 185 | func (f *File) read(b []byte) (n int, err error) { |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 186 | f.l.Lock() |
| 187 | defer f.l.Unlock() |
| 188 | return syscall.Read(f.fd, b) |
| 189 | } |
| 190 | |
| 191 | // pread reads len(b) bytes from the File starting at byte offset off. |
| 192 | // It returns the number of bytes read and the error, if any. |
| 193 | // EOF is signaled by a zero count with err set to 0. |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 194 | func (f *File) pread(b []byte, off int64) (n int, err error) { |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 195 | f.l.Lock() |
| 196 | defer f.l.Unlock() |
| 197 | curoffset, e := syscall.Seek(f.fd, 0, 1) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 198 | if e != nil { |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 199 | return 0, e |
| 200 | } |
| 201 | defer syscall.Seek(f.fd, curoffset, 0) |
| 202 | o := syscall.Overlapped{ |
| 203 | OffsetHigh: uint32(off >> 32), |
| 204 | Offset: uint32(off), |
| 205 | } |
| 206 | var done uint32 |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 207 | e = syscall.ReadFile(syscall.Handle(f.fd), b, &done, &o) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 208 | if e != nil { |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 209 | return 0, e |
| 210 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 211 | return int(done), nil |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 212 | } |
| 213 | |
| 214 | // write writes len(b) bytes to the File. |
| 215 | // It returns the number of bytes written and an error, if any. |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 216 | func (f *File) write(b []byte) (n int, err error) { |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 217 | f.l.Lock() |
| 218 | defer f.l.Unlock() |
| 219 | return syscall.Write(f.fd, b) |
| 220 | } |
| 221 | |
| 222 | // pwrite writes len(b) bytes to the File starting at byte offset off. |
| 223 | // It returns the number of bytes written and an error, if any. |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 224 | func (f *File) pwrite(b []byte, off int64) (n int, err error) { |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 225 | f.l.Lock() |
| 226 | defer f.l.Unlock() |
| 227 | curoffset, e := syscall.Seek(f.fd, 0, 1) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 228 | if e != nil { |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 229 | return 0, e |
| 230 | } |
| 231 | defer syscall.Seek(f.fd, curoffset, 0) |
| 232 | o := syscall.Overlapped{ |
| 233 | OffsetHigh: uint32(off >> 32), |
| 234 | Offset: uint32(off), |
| 235 | } |
| 236 | var done uint32 |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 237 | e = syscall.WriteFile(syscall.Handle(f.fd), b, &done, &o) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 238 | if e != nil { |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 239 | return 0, e |
| 240 | } |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 241 | return int(done), nil |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 242 | } |
| 243 | |
| 244 | // seek sets the offset for the next Read or Write on file to offset, interpreted |
| 245 | // according to whence: 0 means relative to the origin of the file, 1 means |
| 246 | // relative to the current offset, and 2 means relative to the end. |
| 247 | // It returns the new offset and an error, if any. |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 248 | func (f *File) seek(offset int64, whence int) (ret int64, err error) { |
Alex Brainman | b1deb3b | 2011-04-26 18:09:46 +1000 | [diff] [blame] | 249 | f.l.Lock() |
| 250 | defer f.l.Unlock() |
| 251 | return syscall.Seek(f.fd, offset, whence) |
| 252 | } |
| 253 | |
Alex Brainman | fb6b391 | 2010-04-26 23:17:14 -0700 | [diff] [blame] | 254 | // Truncate changes the size of the named file. |
| 255 | // If the file is a symbolic link, it changes the size of the link's target. |
Russ Cox | 08a073a | 2011-11-01 21:49:08 -0400 | [diff] [blame] | 256 | func Truncate(name string, size int64) error { |
Rob Pike | 80c5ef9 | 2011-04-04 23:57:08 -0700 | [diff] [blame] | 257 | f, e := OpenFile(name, O_WRONLY|O_CREATE, 0666) |
Alex Brainman | fb6b391 | 2010-04-26 23:17:14 -0700 | [diff] [blame] | 258 | if e != nil { |
| 259 | return e |
| 260 | } |
| 261 | defer f.Close() |
| 262 | e1 := f.Truncate(size) |
| 263 | if e1 != nil { |
| 264 | return e1 |
| 265 | } |
| 266 | return nil |
| 267 | } |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 268 | |
Alex Brainman | 796a2c1 | 2011-12-20 11:52:20 +1100 | [diff] [blame] | 269 | // Remove removes the named file or directory. |
Rob Pike | be0f6fe | 2012-02-09 16:55:36 +1100 | [diff] [blame] | 270 | // If there is an error, it will be of type *PathError. |
Alex Brainman | 796a2c1 | 2011-12-20 11:52:20 +1100 | [diff] [blame] | 271 | func Remove(name string) error { |
| 272 | p := &syscall.StringToUTF16(name)[0] |
| 273 | |
| 274 | // Go file interface forces us to know whether |
| 275 | // name is a file or directory. Try both. |
| 276 | e := syscall.DeleteFile(p) |
| 277 | if e == nil { |
| 278 | return nil |
| 279 | } |
| 280 | e1 := syscall.RemoveDirectory(p) |
| 281 | if e1 == nil { |
| 282 | return nil |
| 283 | } |
| 284 | |
| 285 | // Both failed: figure out which error to return. |
| 286 | if e1 != e { |
| 287 | a, e2 := syscall.GetFileAttributes(p) |
| 288 | if e2 != nil { |
| 289 | e = e2 |
| 290 | } else { |
| 291 | if a&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { |
| 292 | e = e1 |
| 293 | } |
| 294 | } |
| 295 | } |
| 296 | return &PathError{"remove", name, e} |
| 297 | } |
| 298 | |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 299 | // Pipe returns a connected pair of Files; reads from r return bytes written to w. |
Russ Cox | 08a073a | 2011-11-01 21:49:08 -0400 | [diff] [blame] | 300 | // It returns the files and an error, if any. |
| 301 | func Pipe() (r *File, w *File, err error) { |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 302 | var p [2]syscall.Handle |
| 303 | |
| 304 | // See ../syscall/exec.go for description of lock. |
| 305 | syscall.ForkLock.RLock() |
| 306 | e := syscall.Pipe(p[0:]) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 307 | if e != nil { |
Wei Guangjing | 63b8b948 | 2011-07-01 10:18:07 -0400 | [diff] [blame] | 308 | syscall.ForkLock.RUnlock() |
| 309 | return nil, nil, NewSyscallError("pipe", e) |
| 310 | } |
| 311 | syscall.CloseOnExec(p[0]) |
| 312 | syscall.CloseOnExec(p[1]) |
| 313 | syscall.ForkLock.RUnlock() |
| 314 | |
| 315 | return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil |
| 316 | } |
Russ Cox | 0acd879 | 2011-11-14 14:06:50 -0500 | [diff] [blame] | 317 | |
| 318 | // TempDir returns the default directory to use for temporary files. |
| 319 | func TempDir() string { |
| 320 | const pathSep = '\\' |
Alex Brainman | 0d37998 | 2011-11-15 12:48:22 -0500 | [diff] [blame] | 321 | dirw := make([]uint16, syscall.MAX_PATH) |
Russ Cox | 0acd879 | 2011-11-14 14:06:50 -0500 | [diff] [blame] | 322 | n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0]) |
| 323 | if n > uint32(len(dirw)) { |
| 324 | dirw = make([]uint16, n) |
| 325 | n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0]) |
| 326 | if n > uint32(len(dirw)) { |
| 327 | n = 0 |
| 328 | } |
| 329 | } |
| 330 | if n > 0 && dirw[n-1] == pathSep { |
| 331 | n-- |
| 332 | } |
| 333 | return string(utf16.Decode(dirw[0:n])) |
| 334 | } |