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