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