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