Source file src/pkg/os/file_unix.go
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 "runtime" 9 "syscall" 10 ) 11 12 // File represents an open file descriptor. 13 type File struct { 14 fd int 15 name string 16 dirinfo *dirInfo // nil unless directory being read 17 nepipe int // number of consecutive EPIPE in Write 18 } 19 20 // Fd returns the integer Unix file descriptor referencing the open file. 21 func (file *File) Fd() int { 22 if file == nil { 23 return -1 24 } 25 return file.fd 26 } 27 28 // NewFile returns a new File with the given file descriptor and name. 29 func NewFile(fd int, name string) *File { 30 if fd < 0 { 31 return nil 32 } 33 f := &File{fd: fd, name: name} 34 runtime.SetFinalizer(f, (*File).Close) 35 return f 36 } 37 38 // Auxiliary information if the File describes a directory 39 type dirInfo struct { 40 buf []byte // buffer for directory I/O 41 nbuf int // length of buf; return value from Getdirentries 42 bufp int // location of next record in buf. 43 } 44 45 // DevNull is the name of the operating system's ``null device.'' 46 // On Unix-like systems, it is "/dev/null"; on Windows, "NUL". 47 const DevNull = "/dev/null" 48 49 // OpenFile is the generalized open call; most users will use Open 50 // or Create instead. It opens the named file with specified flag 51 // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful, 52 // methods on the returned File can be used for I/O. 53 // It returns the File and an Error, if any. 54 func OpenFile(name string, flag int, perm uint32) (file *File, err Error) { 55 r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm) 56 if e != 0 { 57 return nil, &PathError{"open", name, Errno(e)} 58 } 59 60 // There's a race here with fork/exec, which we are 61 // content to live with. See ../syscall/exec.go 62 if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported 63 syscall.CloseOnExec(r) 64 } 65 66 return NewFile(r, name), nil 67 } 68 69 // Close closes the File, rendering it unusable for I/O. 70 // It returns an Error, if any. 71 func (file *File) Close() Error { 72 if file == nil || file.fd < 0 { 73 return EINVAL 74 } 75 var err Error 76 if e := syscall.Close(file.fd); e != 0 { 77 err = &PathError{"close", file.name, Errno(e)} 78 } 79 file.fd = -1 // so it can't be closed again 80 81 // no need for a finalizer anymore 82 runtime.SetFinalizer(file, nil) 83 return err 84 } 85 86 // Stat returns the FileInfo structure describing file. 87 // It returns the FileInfo and an error, if any. 88 func (file *File) Stat() (fi *FileInfo, err Error) { 89 var stat syscall.Stat_t 90 e := syscall.Fstat(file.fd, &stat) 91 if e != 0 { 92 return nil, &PathError{"stat", file.name, Errno(e)} 93 } 94 return fileInfoFromStat(file.name, new(FileInfo), &stat, &stat), nil 95 } 96 97 // Readdir reads the contents of the directory associated with file and 98 // returns an array of up to n FileInfo structures, as would be returned 99 // by Lstat, in directory order. Subsequent calls on the same file will yield 100 // further FileInfos. 101 // 102 // If n > 0, Readdir returns at most n FileInfo structures. In this case, if 103 // Readdir returns an empty slice, it will return a non-nil error 104 // explaining why. At the end of a directory, the error is os.EOF. 105 // 106 // If n <= 0, Readdir returns all the FileInfo from the directory in 107 // a single slice. In this case, if Readdir succeeds (reads all 108 // the way to the end of the directory), it returns the slice and a 109 // nil os.Error. If it encounters an error before the end of the 110 // directory, Readdir returns the FileInfo read until that point 111 // and a non-nil error. 112 func (file *File) Readdir(n int) (fi []FileInfo, err Error) { 113 dirname := file.name 114 if dirname == "" { 115 dirname = "." 116 } 117 dirname += "/" 118 names, err := file.Readdirnames(n) 119 fi = make([]FileInfo, len(names)) 120 for i, filename := range names { 121 fip, err := Lstat(dirname + filename) 122 if fip == nil || err != nil { 123 fi[i].Name = filename // rest is already zeroed out 124 } else { 125 fi[i] = *fip 126 } 127 } 128 return 129 } 130 131 // read reads up to len(b) bytes from the File. 132 // It returns the number of bytes read and an error, if any. 133 func (f *File) read(b []byte) (n int, err int) { 134 return syscall.Read(f.fd, b) 135 } 136 137 // pread reads len(b) bytes from the File starting at byte offset off. 138 // It returns the number of bytes read and the error, if any. 139 // EOF is signaled by a zero count with err set to 0. 140 func (f *File) pread(b []byte, off int64) (n int, err int) { 141 return syscall.Pread(f.fd, b, off) 142 } 143 144 // write writes len(b) bytes to the File. 145 // It returns the number of bytes written and an error, if any. 146 func (f *File) write(b []byte) (n int, err int) { 147 return syscall.Write(f.fd, b) 148 } 149 150 // pwrite writes len(b) bytes to the File starting at byte offset off. 151 // It returns the number of bytes written and an error, if any. 152 func (f *File) pwrite(b []byte, off int64) (n int, err int) { 153 return syscall.Pwrite(f.fd, b, off) 154 } 155 156 // seek sets the offset for the next Read or Write on file to offset, interpreted 157 // according to whence: 0 means relative to the origin of the file, 1 means 158 // relative to the current offset, and 2 means relative to the end. 159 // It returns the new offset and an error, if any. 160 func (f *File) seek(offset int64, whence int) (ret int64, err int) { 161 return syscall.Seek(f.fd, offset, whence) 162 } 163 164 // Truncate changes the size of the named file. 165 // If the file is a symbolic link, it changes the size of the link's target. 166 func Truncate(name string, size int64) Error { 167 if e := syscall.Truncate(name, size); e != 0 { 168 return &PathError{"truncate", name, Errno(e)} 169 } 170 return nil 171 } 172 173 // basename removes trailing slashes and the leading directory name from path name 174 func basename(name string) string { 175 i := len(name) - 1 176 // Remove trailing slashes 177 for ; i > 0 && name[i] == '/'; i-- { 178 name = name[:i] 179 } 180 // Remove leading directory name 181 for i--; i >= 0; i-- { 182 if name[i] == '/' { 183 name = name[i+1:] 184 break 185 } 186 } 187 188 return name 189 } 190 191 // Pipe returns a connected pair of Files; reads from r return bytes written to w. 192 // It returns the files and an Error, if any. 193 func Pipe() (r *File, w *File, err Error) { 194 var p [2]int 195 196 // See ../syscall/exec.go for description of lock. 197 syscall.ForkLock.RLock() 198 e := syscall.Pipe(p[0:]) 199 if iserror(e) { 200 syscall.ForkLock.RUnlock() 201 return nil, nil, NewSyscallError("pipe", e) 202 } 203 syscall.CloseOnExec(p[0]) 204 syscall.CloseOnExec(p[1]) 205 syscall.ForkLock.RUnlock() 206 207 return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil 208 }