github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/os/file_windows.go (about) 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 5 package os 6 7 import ( 8 "errors" 9 "internal/syscall/windows" 10 "io" 11 "runtime" 12 "sync" 13 "syscall" 14 "unicode/utf16" 15 "unicode/utf8" 16 "unsafe" 17 ) 18 19 // file is the real representation of *File. 20 // The extra level of indirection ensures that no clients of os 21 // can overwrite this data, which could cause the finalizer 22 // to close the wrong file descriptor. 23 type file struct { 24 fd syscall.Handle 25 name string 26 dirinfo *dirInfo // nil unless directory being read 27 l sync.Mutex // used to implement windows pread/pwrite 28 29 // only for console io 30 isConsole bool 31 lastbits []byte // first few bytes of the last incomplete rune in last write 32 readbuf []byte // last few bytes of the last read that did not fit in the user buffer 33 } 34 35 // Fd returns the Windows handle referencing the open file. 36 // The handle is valid only until f.Close is called or f is garbage collected. 37 func (file *File) Fd() uintptr { 38 if file == nil { 39 return uintptr(syscall.InvalidHandle) 40 } 41 return uintptr(file.fd) 42 } 43 44 // newFile returns a new File with the given file handle and name. 45 // Unlike NewFile, it does not check that h is syscall.InvalidHandle. 46 func newFile(h syscall.Handle, name string) *File { 47 f := &File{&file{fd: h, name: name}} 48 runtime.SetFinalizer(f.file, (*file).close) 49 return f 50 } 51 52 // newConsoleFile creates new File that will be used as console. 53 func newConsoleFile(h syscall.Handle, name string) *File { 54 f := newFile(h, name) 55 f.isConsole = true 56 f.readbuf = make([]byte, 0, 4) 57 return f 58 } 59 60 // NewFile returns a new File with the given file descriptor and name. 61 func NewFile(fd uintptr, name string) *File { 62 h := syscall.Handle(fd) 63 if h == syscall.InvalidHandle { 64 return nil 65 } 66 var m uint32 67 if syscall.GetConsoleMode(h, &m) == nil { 68 return newConsoleFile(h, name) 69 } 70 return newFile(h, name) 71 } 72 73 // Auxiliary information if the File describes a directory 74 type dirInfo struct { 75 data syscall.Win32finddata 76 needdata bool 77 path string 78 isempty bool // set if FindFirstFile returns ERROR_FILE_NOT_FOUND 79 } 80 81 func epipecheck(file *File, e error) { 82 } 83 84 const DevNull = "NUL" 85 86 func (f *file) isdir() bool { return f != nil && f.dirinfo != nil } 87 88 func openFile(name string, flag int, perm FileMode) (file *File, err error) { 89 r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) 90 if e != nil { 91 return nil, e 92 } 93 return NewFile(uintptr(r), name), nil 94 } 95 96 func openDir(name string) (file *File, err error) { 97 var mask string 98 if len(name) == 2 && name[1] == ':' { // it is a drive letter, like C: 99 mask = name + `*` 100 } else { 101 mask = name + `\*` 102 } 103 maskp, e := syscall.UTF16PtrFromString(mask) 104 if e != nil { 105 return nil, e 106 } 107 d := new(dirInfo) 108 r, e := syscall.FindFirstFile(maskp, &d.data) 109 if e != nil { 110 // FindFirstFile returns ERROR_FILE_NOT_FOUND when 111 // no matching files can be found. Then, if directory 112 // exists, we should proceed. 113 if e != syscall.ERROR_FILE_NOT_FOUND { 114 return nil, e 115 } 116 var fa syscall.Win32FileAttributeData 117 namep, e := syscall.UTF16PtrFromString(name) 118 if e != nil { 119 return nil, e 120 } 121 e = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa))) 122 if e != nil { 123 return nil, e 124 } 125 if fa.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY == 0 { 126 return nil, e 127 } 128 d.isempty = true 129 } 130 d.path = name 131 if !isAbs(d.path) { 132 d.path, e = syscall.FullPath(d.path) 133 if e != nil { 134 return nil, e 135 } 136 } 137 f := newFile(r, name) 138 f.dirinfo = d 139 return f, nil 140 } 141 142 // OpenFile is the generalized open call; most users will use Open 143 // or Create instead. It opens the named file with specified flag 144 // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful, 145 // methods on the returned File can be used for I/O. 146 // If there is an error, it will be of type *PathError. 147 func OpenFile(name string, flag int, perm FileMode) (*File, error) { 148 if name == "" { 149 return nil, &PathError{"open", name, syscall.ENOENT} 150 } 151 r, errf := openFile(name, flag, perm) 152 if errf == nil { 153 return r, nil 154 } 155 r, errd := openDir(name) 156 if errd == nil { 157 if flag&O_WRONLY != 0 || flag&O_RDWR != 0 { 158 r.Close() 159 return nil, &PathError{"open", name, syscall.EISDIR} 160 } 161 return r, nil 162 } 163 return nil, &PathError{"open", name, errf} 164 } 165 166 // Close closes the File, rendering it unusable for I/O. 167 // It returns an error, if any. 168 func (file *File) Close() error { 169 if file == nil { 170 return ErrInvalid 171 } 172 return file.file.close() 173 } 174 175 func (file *file) close() error { 176 if file == nil { 177 return syscall.EINVAL 178 } 179 if file.isdir() && file.dirinfo.isempty { 180 // "special" empty directories 181 return nil 182 } 183 if file.fd == syscall.InvalidHandle { 184 return syscall.EINVAL 185 } 186 var e error 187 if file.isdir() { 188 e = syscall.FindClose(file.fd) 189 } else { 190 e = syscall.CloseHandle(file.fd) 191 } 192 var err error 193 if e != nil { 194 err = &PathError{"close", file.name, e} 195 } 196 file.fd = badFd // so it can't be closed again 197 198 // no need for a finalizer anymore 199 runtime.SetFinalizer(file, nil) 200 return err 201 } 202 203 var ( 204 // These variables are used for testing readConsole. 205 getCP = windows.GetConsoleCP 206 readFile = syscall.ReadFile 207 ) 208 209 func resetGetConsoleCPAndReadFileFuncs() { 210 getCP = windows.GetConsoleCP 211 readFile = syscall.ReadFile 212 } 213 214 // copyReadConsoleBuffer copies data stored in f.readbuf into buf. 215 // It adjusts f.readbuf accordingly and returns number of bytes copied. 216 func (f *File) copyReadConsoleBuffer(buf []byte) (n int, err error) { 217 n = copy(buf, f.readbuf) 218 newsize := copy(f.readbuf, f.readbuf[n:]) 219 f.readbuf = f.readbuf[:newsize] 220 return n, nil 221 } 222 223 // readOneUTF16FromConsole reads single character from console, 224 // converts it into utf16 and return it to the caller. 225 func (f *File) readOneUTF16FromConsole() (uint16, error) { 226 var buf [1]byte 227 mbytes := make([]byte, 0, 4) 228 cp := getCP() 229 for { 230 var nmb uint32 231 err := readFile(f.fd, buf[:], &nmb, nil) 232 if err != nil { 233 return 0, err 234 } 235 if nmb == 0 { 236 continue 237 } 238 mbytes = append(mbytes, buf[0]) 239 240 // Convert from 8-bit console encoding to UTF16. 241 // MultiByteToWideChar defaults to Unicode NFC form, which is the expected one. 242 nwc, err := windows.MultiByteToWideChar(cp, windows.MB_ERR_INVALID_CHARS, &mbytes[0], int32(len(mbytes)), nil, 0) 243 if err != nil { 244 if err == windows.ERROR_NO_UNICODE_TRANSLATION { 245 continue 246 } 247 return 0, err 248 } 249 if nwc != 1 { 250 return 0, errors.New("MultiByteToWideChar returns " + itoa(int(nwc)) + " characters, but only 1 expected") 251 } 252 var wchars [1]uint16 253 nwc, err = windows.MultiByteToWideChar(cp, windows.MB_ERR_INVALID_CHARS, &mbytes[0], int32(len(mbytes)), &wchars[0], nwc) 254 if err != nil { 255 return 0, err 256 } 257 return wchars[0], nil 258 } 259 } 260 261 // readConsole reads utf16 characters from console File, 262 // encodes them into utf8 and stores them in buffer buf. 263 // It returns the number of utf8 bytes read and an error, if any. 264 func (f *File) readConsole(buf []byte) (n int, err error) { 265 if len(buf) == 0 { 266 return 0, nil 267 } 268 if len(f.readbuf) > 0 { 269 return f.copyReadConsoleBuffer(buf) 270 } 271 wchar, err := f.readOneUTF16FromConsole() 272 if err != nil { 273 return 0, err 274 } 275 r := rune(wchar) 276 if utf16.IsSurrogate(r) { 277 wchar, err := f.readOneUTF16FromConsole() 278 if err != nil { 279 return 0, err 280 } 281 r = utf16.DecodeRune(r, rune(wchar)) 282 } 283 if nr := utf8.RuneLen(r); nr > len(buf) { 284 start := len(f.readbuf) 285 for ; nr > 0; nr-- { 286 f.readbuf = append(f.readbuf, 0) 287 } 288 utf8.EncodeRune(f.readbuf[start:cap(f.readbuf)], r) 289 } else { 290 utf8.EncodeRune(buf, r) 291 buf = buf[nr:] 292 n += nr 293 } 294 if n > 0 { 295 return n, nil 296 } 297 return f.copyReadConsoleBuffer(buf) 298 } 299 300 // read reads up to len(b) bytes from the File. 301 // It returns the number of bytes read and an error, if any. 302 func (f *File) read(b []byte) (n int, err error) { 303 f.l.Lock() 304 defer f.l.Unlock() 305 if f.isConsole { 306 return f.readConsole(b) 307 } 308 return fixCount(syscall.Read(f.fd, b)) 309 } 310 311 // pread reads len(b) bytes from the File starting at byte offset off. 312 // It returns the number of bytes read and the error, if any. 313 // EOF is signaled by a zero count with err set to 0. 314 func (f *File) pread(b []byte, off int64) (n int, err error) { 315 f.l.Lock() 316 defer f.l.Unlock() 317 curoffset, e := syscall.Seek(f.fd, 0, io.SeekCurrent) 318 if e != nil { 319 return 0, e 320 } 321 defer syscall.Seek(f.fd, curoffset, io.SeekStart) 322 o := syscall.Overlapped{ 323 OffsetHigh: uint32(off >> 32), 324 Offset: uint32(off), 325 } 326 var done uint32 327 e = syscall.ReadFile(f.fd, b, &done, &o) 328 if e != nil { 329 if e == syscall.ERROR_HANDLE_EOF { 330 // end of file 331 return 0, nil 332 } 333 return 0, e 334 } 335 return int(done), nil 336 } 337 338 // writeConsole writes len(b) bytes to the console File. 339 // It returns the number of bytes written and an error, if any. 340 func (f *File) writeConsole(b []byte) (n int, err error) { 341 n = len(b) 342 runes := make([]rune, 0, 256) 343 if len(f.lastbits) > 0 { 344 b = append(f.lastbits, b...) 345 f.lastbits = nil 346 347 } 348 for len(b) >= utf8.UTFMax || utf8.FullRune(b) { 349 r, l := utf8.DecodeRune(b) 350 runes = append(runes, r) 351 b = b[l:] 352 } 353 if len(b) > 0 { 354 f.lastbits = make([]byte, len(b)) 355 copy(f.lastbits, b) 356 } 357 // syscall.WriteConsole seems to fail, if given large buffer. 358 // So limit the buffer to 16000 characters. This number was 359 // discovered by experimenting with syscall.WriteConsole. 360 const maxWrite = 16000 361 for len(runes) > 0 { 362 m := len(runes) 363 if m > maxWrite { 364 m = maxWrite 365 } 366 chunk := runes[:m] 367 runes = runes[m:] 368 uint16s := utf16.Encode(chunk) 369 for len(uint16s) > 0 { 370 var written uint32 371 err = syscall.WriteConsole(f.fd, &uint16s[0], uint32(len(uint16s)), &written, nil) 372 if err != nil { 373 return 0, nil 374 } 375 uint16s = uint16s[written:] 376 } 377 } 378 return n, nil 379 } 380 381 // write writes len(b) bytes to the File. 382 // It returns the number of bytes written and an error, if any. 383 func (f *File) write(b []byte) (n int, err error) { 384 f.l.Lock() 385 defer f.l.Unlock() 386 if f.isConsole { 387 return f.writeConsole(b) 388 } 389 return fixCount(syscall.Write(f.fd, b)) 390 } 391 392 // pwrite writes len(b) bytes to the File starting at byte offset off. 393 // It returns the number of bytes written and an error, if any. 394 func (f *File) pwrite(b []byte, off int64) (n int, err error) { 395 f.l.Lock() 396 defer f.l.Unlock() 397 curoffset, e := syscall.Seek(f.fd, 0, io.SeekCurrent) 398 if e != nil { 399 return 0, e 400 } 401 defer syscall.Seek(f.fd, curoffset, io.SeekStart) 402 o := syscall.Overlapped{ 403 OffsetHigh: uint32(off >> 32), 404 Offset: uint32(off), 405 } 406 var done uint32 407 e = syscall.WriteFile(f.fd, b, &done, &o) 408 if e != nil { 409 return 0, e 410 } 411 return int(done), nil 412 } 413 414 // seek sets the offset for the next Read or Write on file to offset, interpreted 415 // according to whence: 0 means relative to the origin of the file, 1 means 416 // relative to the current offset, and 2 means relative to the end. 417 // It returns the new offset and an error, if any. 418 func (f *File) seek(offset int64, whence int) (ret int64, err error) { 419 f.l.Lock() 420 defer f.l.Unlock() 421 return syscall.Seek(f.fd, offset, whence) 422 } 423 424 // Truncate changes the size of the named file. 425 // If the file is a symbolic link, it changes the size of the link's target. 426 func Truncate(name string, size int64) error { 427 f, e := OpenFile(name, O_WRONLY|O_CREATE, 0666) 428 if e != nil { 429 return e 430 } 431 defer f.Close() 432 e1 := f.Truncate(size) 433 if e1 != nil { 434 return e1 435 } 436 return nil 437 } 438 439 // Remove removes the named file or directory. 440 // If there is an error, it will be of type *PathError. 441 func Remove(name string) error { 442 p, e := syscall.UTF16PtrFromString(name) 443 if e != nil { 444 return &PathError{"remove", name, e} 445 } 446 447 // Go file interface forces us to know whether 448 // name is a file or directory. Try both. 449 e = syscall.DeleteFile(p) 450 if e == nil { 451 return nil 452 } 453 e1 := syscall.RemoveDirectory(p) 454 if e1 == nil { 455 return nil 456 } 457 458 // Both failed: figure out which error to return. 459 if e1 != e { 460 a, e2 := syscall.GetFileAttributes(p) 461 if e2 != nil { 462 e = e2 463 } else { 464 if a&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { 465 e = e1 466 } else if a&syscall.FILE_ATTRIBUTE_READONLY != 0 { 467 if e1 = syscall.SetFileAttributes(p, a&^syscall.FILE_ATTRIBUTE_READONLY); e1 == nil { 468 if e = syscall.DeleteFile(p); e == nil { 469 return nil 470 } 471 } 472 } 473 } 474 } 475 return &PathError{"remove", name, e} 476 } 477 478 func rename(oldname, newname string) error { 479 e := windows.Rename(oldname, newname) 480 if e != nil { 481 return &LinkError{"rename", oldname, newname, e} 482 } 483 return nil 484 } 485 486 // Pipe returns a connected pair of Files; reads from r return bytes written to w. 487 // It returns the files and an error, if any. 488 func Pipe() (r *File, w *File, err error) { 489 var p [2]syscall.Handle 490 491 // See ../syscall/exec.go for description of lock. 492 syscall.ForkLock.RLock() 493 e := syscall.Pipe(p[0:]) 494 if e != nil { 495 syscall.ForkLock.RUnlock() 496 return nil, nil, NewSyscallError("pipe", e) 497 } 498 syscall.CloseOnExec(p[0]) 499 syscall.CloseOnExec(p[1]) 500 syscall.ForkLock.RUnlock() 501 502 return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil 503 } 504 505 // TempDir returns the default directory to use for temporary files. 506 func TempDir() string { 507 n := uint32(syscall.MAX_PATH) 508 for { 509 b := make([]uint16, n) 510 n, _ = syscall.GetTempPath(uint32(len(b)), &b[0]) 511 if n > uint32(len(b)) { 512 continue 513 } 514 if n > 0 && b[n-1] == '\\' { 515 n-- 516 } 517 return string(utf16.Decode(b[:n])) 518 } 519 } 520 521 // Link creates newname as a hard link to the oldname file. 522 // If there is an error, it will be of type *LinkError. 523 func Link(oldname, newname string) error { 524 n, err := syscall.UTF16PtrFromString(newname) 525 if err != nil { 526 return &LinkError{"link", oldname, newname, err} 527 } 528 o, err := syscall.UTF16PtrFromString(oldname) 529 if err != nil { 530 return &LinkError{"link", oldname, newname, err} 531 } 532 err = syscall.CreateHardLink(n, o, 0) 533 if err != nil { 534 return &LinkError{"link", oldname, newname, err} 535 } 536 return nil 537 } 538 539 // Symlink creates newname as a symbolic link to oldname. 540 // If there is an error, it will be of type *LinkError. 541 func Symlink(oldname, newname string) error { 542 // CreateSymbolicLink is not supported before Windows Vista 543 if syscall.LoadCreateSymbolicLink() != nil { 544 return &LinkError{"symlink", oldname, newname, syscall.EWINDOWS} 545 } 546 547 // '/' does not work in link's content 548 oldname = fromSlash(oldname) 549 550 // need the exact location of the oldname when its relative to determine if its a directory 551 destpath := oldname 552 if !isAbs(oldname) { 553 destpath = dirname(newname) + `\` + oldname 554 } 555 556 fi, err := Lstat(destpath) 557 isdir := err == nil && fi.IsDir() 558 559 n, err := syscall.UTF16PtrFromString(newname) 560 if err != nil { 561 return &LinkError{"symlink", oldname, newname, err} 562 } 563 o, err := syscall.UTF16PtrFromString(oldname) 564 if err != nil { 565 return &LinkError{"symlink", oldname, newname, err} 566 } 567 568 var flags uint32 569 if isdir { 570 flags |= syscall.SYMBOLIC_LINK_FLAG_DIRECTORY 571 } 572 err = syscall.CreateSymbolicLink(n, o, flags) 573 if err != nil { 574 return &LinkError{"symlink", oldname, newname, err} 575 } 576 return nil 577 } 578 579 const badFd = syscall.InvalidHandle