github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/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 } 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 // It returns an error, if any. 137 func (f *File) Close() error { 138 if err := f.checkValid("close"); err != nil { 139 return err 140 } 141 return f.file.close() 142 } 143 144 func (file *file) close() error { 145 if file == nil || file.fd == badFd { 146 return ErrInvalid 147 } 148 var err error 149 if e := syscall.Close(file.fd); e != nil { 150 err = &PathError{"close", file.name, e} 151 } 152 file.fd = badFd // so it can't be closed again 153 154 // no need for a finalizer anymore 155 runtime.SetFinalizer(file, nil) 156 return err 157 } 158 159 // Stat returns the FileInfo structure describing file. 160 // If there is an error, it will be of type *PathError. 161 func (f *File) Stat() (FileInfo, error) { 162 if f == nil { 163 return nil, ErrInvalid 164 } 165 d, err := dirstat(f) 166 if err != nil { 167 return nil, err 168 } 169 return fileInfoFromStat(d), nil 170 } 171 172 // Truncate changes the size of the file. 173 // It does not change the I/O offset. 174 // If there is an error, it will be of type *PathError. 175 func (f *File) Truncate(size int64) error { 176 if f == nil { 177 return ErrInvalid 178 } 179 180 var d syscall.Dir 181 d.Null() 182 d.Length = size 183 184 var buf [syscall.STATFIXLEN]byte 185 n, err := d.Marshal(buf[:]) 186 if err != nil { 187 return &PathError{"truncate", f.name, err} 188 } 189 if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { 190 return &PathError{"truncate", f.name, err} 191 } 192 return nil 193 } 194 195 const chmodMask = uint32(syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm) 196 197 func (f *File) chmod(mode FileMode) error { 198 if f == nil { 199 return ErrInvalid 200 } 201 var d syscall.Dir 202 203 odir, e := dirstat(f) 204 if e != nil { 205 return &PathError{"chmod", f.name, e} 206 } 207 d.Null() 208 d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask 209 210 var buf [syscall.STATFIXLEN]byte 211 n, err := d.Marshal(buf[:]) 212 if err != nil { 213 return &PathError{"chmod", f.name, err} 214 } 215 if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { 216 return &PathError{"chmod", f.name, err} 217 } 218 return nil 219 } 220 221 // Sync commits the current contents of the file to stable storage. 222 // Typically, this means flushing the file system's in-memory copy 223 // of recently written data to disk. 224 func (f *File) Sync() error { 225 if f == nil { 226 return ErrInvalid 227 } 228 var d syscall.Dir 229 d.Null() 230 231 var buf [syscall.STATFIXLEN]byte 232 n, err := d.Marshal(buf[:]) 233 if err != nil { 234 return NewSyscallError("fsync", err) 235 } 236 if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { 237 return NewSyscallError("fsync", err) 238 } 239 return nil 240 } 241 242 // read reads up to len(b) bytes from the File. 243 // It returns the number of bytes read and an error, if any. 244 func (f *File) read(b []byte) (n int, err error) { 245 n, e := fixCount(syscall.Read(f.fd, b)) 246 if n == 0 && len(b) > 0 && e == nil { 247 return 0, io.EOF 248 } 249 return n, e 250 } 251 252 // pread reads len(b) bytes from the File starting at byte offset off. 253 // It returns the number of bytes read and the error, if any. 254 // EOF is signaled by a zero count with err set to nil. 255 func (f *File) pread(b []byte, off int64) (n int, err error) { 256 n, e := fixCount(syscall.Pread(f.fd, b, off)) 257 if n == 0 && len(b) > 0 && e == nil { 258 return 0, io.EOF 259 } 260 return n, e 261 } 262 263 // write writes len(b) bytes to the File. 264 // It returns the number of bytes written and an error, if any. 265 // Since Plan 9 preserves message boundaries, never allow 266 // a zero-byte write. 267 func (f *File) write(b []byte) (n int, err error) { 268 if len(b) == 0 { 269 return 0, nil 270 } 271 return fixCount(syscall.Write(f.fd, b)) 272 } 273 274 // pwrite writes len(b) bytes to the File starting at byte offset off. 275 // It returns the number of bytes written and an error, if any. 276 // Since Plan 9 preserves message boundaries, never allow 277 // a zero-byte write. 278 func (f *File) pwrite(b []byte, off int64) (n int, err error) { 279 if len(b) == 0 { 280 return 0, nil 281 } 282 return fixCount(syscall.Pwrite(f.fd, b, off)) 283 } 284 285 // seek sets the offset for the next Read or Write on file to offset, interpreted 286 // according to whence: 0 means relative to the origin of the file, 1 means 287 // relative to the current offset, and 2 means relative to the end. 288 // It returns the new offset and an error, if any. 289 func (f *File) seek(offset int64, whence int) (ret int64, err error) { 290 return syscall.Seek(f.fd, offset, whence) 291 } 292 293 // Truncate changes the size of the named file. 294 // If the file is a symbolic link, it changes the size of the link's target. 295 // If there is an error, it will be of type *PathError. 296 func Truncate(name string, size int64) error { 297 var d syscall.Dir 298 299 d.Null() 300 d.Length = size 301 302 var buf [syscall.STATFIXLEN]byte 303 n, err := d.Marshal(buf[:]) 304 if err != nil { 305 return &PathError{"truncate", name, err} 306 } 307 if err = syscall.Wstat(name, buf[:n]); err != nil { 308 return &PathError{"truncate", name, err} 309 } 310 return nil 311 } 312 313 // Remove removes the named file or directory. 314 // If there is an error, it will be of type *PathError. 315 func Remove(name string) error { 316 if e := syscall.Remove(name); e != nil { 317 return &PathError{"remove", name, e} 318 } 319 return nil 320 } 321 322 // HasPrefix from the strings package. 323 func hasPrefix(s, prefix string) bool { 324 return len(s) >= len(prefix) && s[0:len(prefix)] == prefix 325 } 326 327 // LastIndexByte from the strings package. 328 func lastIndex(s string, sep byte) int { 329 for i := len(s) - 1; i >= 0; i-- { 330 if s[i] == sep { 331 return i 332 } 333 } 334 return -1 335 } 336 337 func rename(oldname, newname string) error { 338 dirname := oldname[:lastIndex(oldname, '/')+1] 339 if hasPrefix(newname, dirname) { 340 newname = newname[len(dirname):] 341 } else { 342 return &LinkError{"rename", oldname, newname, ErrInvalid} 343 } 344 345 // If newname still contains slashes after removing the oldname 346 // prefix, the rename is cross-directory and must be rejected. 347 if lastIndex(newname, '/') >= 0 { 348 return &LinkError{"rename", oldname, newname, ErrInvalid} 349 } 350 351 var d syscall.Dir 352 353 d.Null() 354 d.Name = newname 355 356 buf := make([]byte, syscall.STATFIXLEN+len(d.Name)) 357 n, err := d.Marshal(buf[:]) 358 if err != nil { 359 return &LinkError{"rename", oldname, newname, err} 360 } 361 362 // If newname already exists and is not a directory, rename replaces it. 363 f, err := Stat(dirname + newname) 364 if err == nil && !f.IsDir() { 365 Remove(dirname + newname) 366 } 367 368 if err = syscall.Wstat(oldname, buf[:n]); err != nil { 369 return &LinkError{"rename", oldname, newname, err} 370 } 371 return nil 372 } 373 374 // See docs in file.go:Chmod. 375 func chmod(name string, mode FileMode) error { 376 var d syscall.Dir 377 378 odir, e := dirstat(name) 379 if e != nil { 380 return &PathError{"chmod", name, e} 381 } 382 d.Null() 383 d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask 384 385 var buf [syscall.STATFIXLEN]byte 386 n, err := d.Marshal(buf[:]) 387 if err != nil { 388 return &PathError{"chmod", name, err} 389 } 390 if err = syscall.Wstat(name, buf[:n]); err != nil { 391 return &PathError{"chmod", name, err} 392 } 393 return nil 394 } 395 396 // Chtimes changes the access and modification times of the named 397 // file, similar to the Unix utime() or utimes() functions. 398 // 399 // The underlying filesystem may truncate or round the values to a 400 // less precise time unit. 401 // If there is an error, it will be of type *PathError. 402 func Chtimes(name string, atime time.Time, mtime time.Time) error { 403 var d syscall.Dir 404 405 d.Null() 406 d.Atime = uint32(atime.Unix()) 407 d.Mtime = uint32(mtime.Unix()) 408 409 var buf [syscall.STATFIXLEN]byte 410 n, err := d.Marshal(buf[:]) 411 if err != nil { 412 return &PathError{"chtimes", name, err} 413 } 414 if err = syscall.Wstat(name, buf[:n]); err != nil { 415 return &PathError{"chtimes", name, err} 416 } 417 return nil 418 } 419 420 // Pipe returns a connected pair of Files; reads from r return bytes 421 // written to w. It returns the files and an error, if any. 422 func Pipe() (r *File, w *File, err error) { 423 var p [2]int 424 425 if e := syscall.Pipe(p[0:]); e != nil { 426 return nil, nil, NewSyscallError("pipe", e) 427 } 428 429 return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil 430 } 431 432 // not supported on Plan 9 433 434 // Link creates newname as a hard link to the oldname file. 435 // If there is an error, it will be of type *LinkError. 436 func Link(oldname, newname string) error { 437 return &LinkError{"link", oldname, newname, syscall.EPLAN9} 438 } 439 440 // Symlink creates newname as a symbolic link to oldname. 441 // If there is an error, it will be of type *LinkError. 442 func Symlink(oldname, newname string) error { 443 return &LinkError{"symlink", oldname, newname, syscall.EPLAN9} 444 } 445 446 // Readlink returns the destination of the named symbolic link. 447 // If there is an error, it will be of type *PathError. 448 func Readlink(name string) (string, error) { 449 return "", &PathError{"readlink", name, syscall.EPLAN9} 450 } 451 452 // Chown changes the numeric uid and gid of the named file. 453 // If the file is a symbolic link, it changes the uid and gid of the link's target. 454 // If there is an error, it will be of type *PathError. 455 func Chown(name string, uid, gid int) error { 456 return &PathError{"chown", name, syscall.EPLAN9} 457 } 458 459 // Lchown changes the numeric uid and gid of the named file. 460 // If the file is a symbolic link, it changes the uid and gid of the link itself. 461 // If there is an error, it will be of type *PathError. 462 func Lchown(name string, uid, gid int) error { 463 return &PathError{"lchown", name, syscall.EPLAN9} 464 } 465 466 // Chown changes the numeric uid and gid of the named file. 467 // If there is an error, it will be of type *PathError. 468 func (f *File) Chown(uid, gid int) error { 469 if f == nil { 470 return ErrInvalid 471 } 472 return &PathError{"chown", f.name, syscall.EPLAN9} 473 } 474 475 func tempDir() string { 476 return "/tmp" 477 } 478 479 // Chdir changes the current working directory to the file, 480 // which must be a directory. 481 // If there is an error, it will be of type *PathError. 482 func (f *File) Chdir() error { 483 if err := f.checkValid("chdir"); err != nil { 484 return err 485 } 486 if e := syscall.Fchdir(f.fd); e != nil { 487 return &PathError{"chdir", f.name, e} 488 } 489 return nil 490 } 491 492 // setDeadline sets the read and write deadline. 493 func (f *File) setDeadline(time.Time) error { 494 if err := f.checkValid("SetDeadline"); err != nil { 495 return err 496 } 497 return poll.ErrNoDeadline 498 } 499 500 // setReadDeadline sets the read deadline. 501 func (f *File) setReadDeadline(time.Time) error { 502 if err := f.checkValid("SetReadDeadline"); err != nil { 503 return err 504 } 505 return poll.ErrNoDeadline 506 } 507 508 // setWriteDeadline sets the write deadline. 509 func (f *File) setWriteDeadline(time.Time) error { 510 if err := f.checkValid("SetWriteDeadline"); err != nil { 511 return err 512 } 513 return poll.ErrNoDeadline 514 } 515 516 // checkValid checks whether f is valid for use. 517 // If not, it returns an appropriate error, perhaps incorporating the operation name op. 518 func (f *File) checkValid(op string) error { 519 if f == nil { 520 return ErrInvalid 521 } 522 if f.fd == badFd { 523 return &PathError{op, f.name, ErrClosed} 524 } 525 return nil 526 }