github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/os/file_plan9.go (about) 1 // Copyright 2011 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/poll" 9 "io" 10 "runtime" 11 "syscall" 12 "time" 13 ) 14 15 // fixLongPath is a noop on non-Windows platforms. 16 func fixLongPath(path string) string { 17 return path 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 { 25 fd int 26 name string 27 dirinfo *dirInfo // nil unless directory being read 28 appendMode bool // whether file is opened for appending 29 } 30 31 // Fd returns the integer Plan 9 file descriptor referencing the open file. 32 // If f is closed, the file descriptor becomes invalid. 33 // If f is garbage collected, a finalizer may close the file descriptor, 34 // making it invalid; see runtime.SetFinalizer for more information on when 35 // a finalizer might be run. On Unix systems this will cause the SetDeadline 36 // methods to stop working. 37 // 38 // As an alternative, see the f.SyscallConn method. 39 func (f *File) Fd() uintptr { 40 if f == nil { 41 return ^(uintptr(0)) 42 } 43 return uintptr(f.fd) 44 } 45 46 // NewFile returns a new File with the given file descriptor and 47 // name. The returned value will be nil if fd is not a valid file 48 // descriptor. 49 func NewFile(fd uintptr, name string) *File { 50 fdi := int(fd) 51 if fdi < 0 { 52 return nil 53 } 54 f := &File{&file{fd: fdi, name: name}} 55 runtime.SetFinalizer(f.file, (*file).close) 56 return f 57 } 58 59 // Auxiliary information if the File describes a directory 60 type dirInfo struct { 61 buf [syscall.STATMAX]byte // buffer for directory I/O 62 nbuf int // length of buf; return value from Read 63 bufp int // location of next record in buf. 64 } 65 66 func epipecheck(file *File, e error) { 67 } 68 69 // DevNull is the name of the operating system's ``null device.'' 70 // On Unix-like systems, it is "/dev/null"; on Windows, "NUL". 71 const DevNull = "/dev/null" 72 73 // syscallMode returns the syscall-specific mode bits from Go's portable mode bits. 74 func syscallMode(i FileMode) (o uint32) { 75 o |= uint32(i.Perm()) 76 if i&ModeAppend != 0 { 77 o |= syscall.DMAPPEND 78 } 79 if i&ModeExclusive != 0 { 80 o |= syscall.DMEXCL 81 } 82 if i&ModeTemporary != 0 { 83 o |= syscall.DMTMP 84 } 85 return 86 } 87 88 // openFileNolog is the Plan 9 implementation of OpenFile. 89 func openFileNolog(name string, flag int, perm FileMode) (*File, error) { 90 var ( 91 fd int 92 e error 93 create bool 94 excl bool 95 trunc bool 96 append bool 97 ) 98 99 if flag&O_CREATE == O_CREATE { 100 flag = flag & ^O_CREATE 101 create = true 102 } 103 if flag&O_EXCL == O_EXCL { 104 excl = true 105 } 106 if flag&O_TRUNC == O_TRUNC { 107 trunc = true 108 } 109 // O_APPEND is emulated on Plan 9 110 if flag&O_APPEND == O_APPEND { 111 flag = flag &^ O_APPEND 112 append = true 113 } 114 115 if (create && trunc) || excl { 116 fd, e = syscall.Create(name, flag, syscallMode(perm)) 117 } else { 118 fd, e = syscall.Open(name, flag) 119 if IsNotExist(e) && create { 120 fd, e = syscall.Create(name, flag, syscallMode(perm)) 121 if e != nil { 122 return nil, &PathError{Op: "create", Path: name, Err: e} 123 } 124 } 125 } 126 127 if e != nil { 128 return nil, &PathError{Op: "open", Path: name, Err: e} 129 } 130 131 if append { 132 if _, e = syscall.Seek(fd, 0, io.SeekEnd); e != nil { 133 return nil, &PathError{Op: "seek", Path: name, Err: e} 134 } 135 } 136 137 return NewFile(uintptr(fd), name), nil 138 } 139 140 // Close closes the File, rendering it unusable for I/O. 141 // On files that support SetDeadline, any pending I/O operations will 142 // be canceled and return immediately with an error. 143 // Close will return an error if it has already been called. 144 func (f *File) Close() error { 145 if err := f.checkValid("close"); err != nil { 146 return err 147 } 148 return f.file.close() 149 } 150 151 func (file *file) close() error { 152 if file == nil || file.fd == badFd { 153 return ErrInvalid 154 } 155 var err error 156 if e := syscall.Close(file.fd); e != nil { 157 err = &PathError{Op: "close", Path: file.name, Err: e} 158 } 159 file.fd = badFd // so it can't be closed again 160 161 // no need for a finalizer anymore 162 runtime.SetFinalizer(file, nil) 163 return err 164 } 165 166 // Stat returns the FileInfo structure describing file. 167 // If there is an error, it will be of type *PathError. 168 func (f *File) Stat() (FileInfo, error) { 169 if f == nil { 170 return nil, ErrInvalid 171 } 172 d, err := dirstat(f) 173 if err != nil { 174 return nil, err 175 } 176 return fileInfoFromStat(d), nil 177 } 178 179 // Truncate changes the size of the file. 180 // It does not change the I/O offset. 181 // If there is an error, it will be of type *PathError. 182 func (f *File) Truncate(size int64) error { 183 if f == nil { 184 return ErrInvalid 185 } 186 187 var d syscall.Dir 188 d.Null() 189 d.Length = size 190 191 var buf [syscall.STATFIXLEN]byte 192 n, err := d.Marshal(buf[:]) 193 if err != nil { 194 return &PathError{Op: "truncate", Path: f.name, Err: err} 195 } 196 if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { 197 return &PathError{Op: "truncate", Path: f.name, Err: err} 198 } 199 return nil 200 } 201 202 const chmodMask = uint32(syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm) 203 204 func (f *File) chmod(mode FileMode) error { 205 if f == nil { 206 return ErrInvalid 207 } 208 var d syscall.Dir 209 210 odir, e := dirstat(f) 211 if e != nil { 212 return &PathError{Op: "chmod", Path: f.name, Err: e} 213 } 214 d.Null() 215 d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask 216 217 var buf [syscall.STATFIXLEN]byte 218 n, err := d.Marshal(buf[:]) 219 if err != nil { 220 return &PathError{Op: "chmod", Path: f.name, Err: err} 221 } 222 if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { 223 return &PathError{Op: "chmod", Path: f.name, Err: err} 224 } 225 return nil 226 } 227 228 // Sync commits the current contents of the file to stable storage. 229 // Typically, this means flushing the file system's in-memory copy 230 // of recently written data to disk. 231 func (f *File) Sync() error { 232 if f == nil { 233 return ErrInvalid 234 } 235 var d syscall.Dir 236 d.Null() 237 238 var buf [syscall.STATFIXLEN]byte 239 n, err := d.Marshal(buf[:]) 240 if err != nil { 241 return &PathError{Op: "sync", Path: f.name, Err: err} 242 } 243 if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { 244 return &PathError{Op: "sync", Path: f.name, Err: err} 245 } 246 return nil 247 } 248 249 // read reads up to len(b) bytes from the File. 250 // It returns the number of bytes read and an error, if any. 251 func (f *File) read(b []byte) (n int, err error) { 252 n, e := fixCount(syscall.Read(f.fd, b)) 253 if n == 0 && len(b) > 0 && e == nil { 254 return 0, io.EOF 255 } 256 return n, e 257 } 258 259 // pread reads len(b) bytes from the File starting at byte offset off. 260 // It returns the number of bytes read and the error, if any. 261 // EOF is signaled by a zero count with err set to nil. 262 func (f *File) pread(b []byte, off int64) (n int, err error) { 263 n, e := fixCount(syscall.Pread(f.fd, b, off)) 264 if n == 0 && len(b) > 0 && e == nil { 265 return 0, io.EOF 266 } 267 return n, e 268 } 269 270 // write writes len(b) bytes to the File. 271 // It returns the number of bytes written and an error, if any. 272 // Since Plan 9 preserves message boundaries, never allow 273 // a zero-byte write. 274 func (f *File) write(b []byte) (n int, err error) { 275 if len(b) == 0 { 276 return 0, nil 277 } 278 return fixCount(syscall.Write(f.fd, b)) 279 } 280 281 // pwrite writes len(b) bytes to the File starting at byte offset off. 282 // It returns the number of bytes written and an error, if any. 283 // Since Plan 9 preserves message boundaries, never allow 284 // a zero-byte write. 285 func (f *File) pwrite(b []byte, off int64) (n int, err error) { 286 if len(b) == 0 { 287 return 0, nil 288 } 289 return fixCount(syscall.Pwrite(f.fd, b, off)) 290 } 291 292 // seek sets the offset for the next Read or Write on file to offset, interpreted 293 // according to whence: 0 means relative to the origin of the file, 1 means 294 // relative to the current offset, and 2 means relative to the end. 295 // It returns the new offset and an error, if any. 296 func (f *File) seek(offset int64, whence int) (ret int64, err error) { 297 if f.dirinfo != nil { 298 // Free cached dirinfo, so we allocate a new one if we 299 // access this file as a directory again. See #35767 and #37161. 300 f.dirinfo = nil 301 } 302 return syscall.Seek(f.fd, offset, whence) 303 } 304 305 // Truncate changes the size of the named file. 306 // If the file is a symbolic link, it changes the size of the link's target. 307 // If there is an error, it will be of type *PathError. 308 func Truncate(name string, size int64) error { 309 var d syscall.Dir 310 311 d.Null() 312 d.Length = size 313 314 var buf [syscall.STATFIXLEN]byte 315 n, err := d.Marshal(buf[:]) 316 if err != nil { 317 return &PathError{Op: "truncate", Path: name, Err: err} 318 } 319 if err = syscall.Wstat(name, buf[:n]); err != nil { 320 return &PathError{Op: "truncate", Path: name, Err: err} 321 } 322 return nil 323 } 324 325 // Remove removes the named file or directory. 326 // If there is an error, it will be of type *PathError. 327 func Remove(name string) error { 328 if e := syscall.Remove(name); e != nil { 329 return &PathError{Op: "remove", Path: name, Err: e} 330 } 331 return nil 332 } 333 334 // HasPrefix from the strings package. 335 func hasPrefix(s, prefix string) bool { 336 return len(s) >= len(prefix) && s[0:len(prefix)] == prefix 337 } 338 339 func rename(oldname, newname string) error { 340 dirname := oldname[:lastIndex(oldname, '/')+1] 341 if hasPrefix(newname, dirname) { 342 newname = newname[len(dirname):] 343 } else { 344 return &LinkError{"rename", oldname, newname, ErrInvalid} 345 } 346 347 // If newname still contains slashes after removing the oldname 348 // prefix, the rename is cross-directory and must be rejected. 349 if lastIndex(newname, '/') >= 0 { 350 return &LinkError{"rename", oldname, newname, ErrInvalid} 351 } 352 353 var d syscall.Dir 354 355 d.Null() 356 d.Name = newname 357 358 buf := make([]byte, syscall.STATFIXLEN+len(d.Name)) 359 n, err := d.Marshal(buf[:]) 360 if err != nil { 361 return &LinkError{"rename", oldname, newname, err} 362 } 363 364 // If newname already exists and is not a directory, rename replaces it. 365 f, err := Stat(dirname + newname) 366 if err == nil && !f.IsDir() { 367 Remove(dirname + newname) 368 } 369 370 if err = syscall.Wstat(oldname, buf[:n]); err != nil { 371 return &LinkError{"rename", oldname, newname, err} 372 } 373 return nil 374 } 375 376 // See docs in file.go:Chmod. 377 func chmod(name string, mode FileMode) error { 378 var d syscall.Dir 379 380 odir, e := dirstat(name) 381 if e != nil { 382 return &PathError{Op: "chmod", Path: name, Err: e} 383 } 384 d.Null() 385 d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask 386 387 var buf [syscall.STATFIXLEN]byte 388 n, err := d.Marshal(buf[:]) 389 if err != nil { 390 return &PathError{Op: "chmod", Path: name, Err: err} 391 } 392 if err = syscall.Wstat(name, buf[:n]); err != nil { 393 return &PathError{Op: "chmod", Path: name, Err: err} 394 } 395 return nil 396 } 397 398 // Chtimes changes the access and modification times of the named 399 // file, similar to the Unix utime() or utimes() functions. 400 // 401 // The underlying filesystem may truncate or round the values to a 402 // less precise time unit. 403 // If there is an error, it will be of type *PathError. 404 func Chtimes(name string, atime time.Time, mtime time.Time) error { 405 var d syscall.Dir 406 407 d.Null() 408 d.Atime = uint32(atime.Unix()) 409 d.Mtime = uint32(mtime.Unix()) 410 411 var buf [syscall.STATFIXLEN]byte 412 n, err := d.Marshal(buf[:]) 413 if err != nil { 414 return &PathError{Op: "chtimes", Path: name, Err: err} 415 } 416 if err = syscall.Wstat(name, buf[:n]); err != nil { 417 return &PathError{Op: "chtimes", Path: name, Err: err} 418 } 419 return nil 420 } 421 422 // Pipe returns a connected pair of Files; reads from r return bytes 423 // written to w. It returns the files and an error, if any. 424 func Pipe() (r *File, w *File, err error) { 425 var p [2]int 426 427 if e := syscall.Pipe(p[0:]); e != nil { 428 return nil, nil, NewSyscallError("pipe", e) 429 } 430 431 return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil 432 } 433 434 // not supported on Plan 9 435 436 // Link creates newname as a hard link to the oldname file. 437 // If there is an error, it will be of type *LinkError. 438 func Link(oldname, newname string) error { 439 return &LinkError{"link", oldname, newname, syscall.EPLAN9} 440 } 441 442 // Symlink creates newname as a symbolic link to oldname. 443 // On Windows, a symlink to a non-existent oldname creates a file symlink; 444 // if oldname is later created as a directory the symlink will not work. 445 // If there is an error, it will be of type *LinkError. 446 func Symlink(oldname, newname string) error { 447 return &LinkError{"symlink", oldname, newname, syscall.EPLAN9} 448 } 449 450 // Readlink returns the destination of the named symbolic link. 451 // If there is an error, it will be of type *PathError. 452 func Readlink(name string) (string, error) { 453 return "", &PathError{Op: "readlink", Path: name, Err: syscall.EPLAN9} 454 } 455 456 // Chown changes the numeric uid and gid of the named file. 457 // If the file is a symbolic link, it changes the uid and gid of the link's target. 458 // A uid or gid of -1 means to not change that value. 459 // If there is an error, it will be of type *PathError. 460 // 461 // On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or 462 // EPLAN9 error, wrapped in *PathError. 463 func Chown(name string, uid, gid int) error { 464 return &PathError{Op: "chown", Path: name, Err: syscall.EPLAN9} 465 } 466 467 // Lchown changes the numeric uid and gid of the named file. 468 // If the file is a symbolic link, it changes the uid and gid of the link itself. 469 // If there is an error, it will be of type *PathError. 470 func Lchown(name string, uid, gid int) error { 471 return &PathError{Op: "lchown", Path: name, Err: syscall.EPLAN9} 472 } 473 474 // Chown changes the numeric uid and gid of the named file. 475 // If there is an error, it will be of type *PathError. 476 func (f *File) Chown(uid, gid int) error { 477 if f == nil { 478 return ErrInvalid 479 } 480 return &PathError{Op: "chown", Path: f.name, Err: syscall.EPLAN9} 481 } 482 483 func tempDir() string { 484 dir := Getenv("TMPDIR") 485 if dir == "" { 486 dir = "/tmp" 487 } 488 return dir 489 490 } 491 492 // Chdir changes the current working directory to the file, 493 // which must be a directory. 494 // If there is an error, it will be of type *PathError. 495 func (f *File) Chdir() error { 496 if err := f.checkValid("chdir"); err != nil { 497 return err 498 } 499 if e := syscall.Fchdir(f.fd); e != nil { 500 return &PathError{Op: "chdir", Path: f.name, Err: e} 501 } 502 return nil 503 } 504 505 // setDeadline sets the read and write deadline. 506 func (f *File) setDeadline(time.Time) error { 507 if err := f.checkValid("SetDeadline"); err != nil { 508 return err 509 } 510 return poll.ErrNoDeadline 511 } 512 513 // setReadDeadline sets the read deadline. 514 func (f *File) setReadDeadline(time.Time) error { 515 if err := f.checkValid("SetReadDeadline"); err != nil { 516 return err 517 } 518 return poll.ErrNoDeadline 519 } 520 521 // setWriteDeadline sets the write deadline. 522 func (f *File) setWriteDeadline(time.Time) error { 523 if err := f.checkValid("SetWriteDeadline"); err != nil { 524 return err 525 } 526 return poll.ErrNoDeadline 527 } 528 529 // checkValid checks whether f is valid for use. 530 // If not, it returns an appropriate error, perhaps incorporating the operation name op. 531 func (f *File) checkValid(op string) error { 532 if f == nil { 533 return ErrInvalid 534 } 535 if f.fd == badFd { 536 return &PathError{Op: op, Path: f.name, Err: ErrClosed} 537 } 538 return nil 539 } 540 541 type rawConn struct{} 542 543 func (c *rawConn) Control(f func(uintptr)) error { 544 return syscall.EPLAN9 545 } 546 547 func (c *rawConn) Read(f func(uintptr) bool) error { 548 return syscall.EPLAN9 549 } 550 551 func (c *rawConn) Write(f func(uintptr) bool) error { 552 return syscall.EPLAN9 553 } 554 555 func newRawConn(file *File) (*rawConn, error) { 556 return nil, syscall.EPLAN9 557 } 558 559 func ignoringEINTR(fn func() error) error { 560 return fn() 561 }