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