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.
15 // fixLongPath is a noop on non-Windows platforms.
16 func fixLongPath(path
string) string {
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.
27 dirinfo
*dirInfo
// nil unless directory being read
28 appendMode
bool // whether file is opened for appending
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.
38 // As an alternative, see the f.SyscallConn method.
39 func (f
*File
) Fd() uintptr {
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
49 func NewFile(fd
uintptr, name
string) *File
{
54 f
:= &File
{&file
{fd
: fdi
, name
: name
}}
55 runtime
.SetFinalizer(f
.file
, (*file
).close)
59 // Auxiliary information if the File describes a directory
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.
66 func epipecheck(file
*File
, e error
) {
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"
73 // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
74 func syscallMode(i FileMode
) (o
uint32) {
76 if i
&ModeAppend
!= 0 {
79 if i
&ModeExclusive
!= 0 {
82 if i
&ModeTemporary
!= 0 {
88 // openFileNolog is the Plan 9 implementation of OpenFile.
89 func openFileNolog(name
string, flag
int, perm FileMode
) (*File
, error
) {
99 if flag
&O_CREATE
== O_CREATE
{
100 flag
= flag
& ^O_CREATE
103 if flag
&O_EXCL
== O_EXCL
{
106 if flag
&O_TRUNC
== O_TRUNC
{
109 // O_APPEND is emulated on Plan 9
110 if flag
&O_APPEND
== O_APPEND
{
111 flag
= flag
&^ O_APPEND
115 if (create
&& trunc
) || excl
{
116 fd
, e
= syscall
.Create(name
, flag
, syscallMode(perm
))
118 fd
, e
= syscall
.Open(name
, flag
)
119 if IsNotExist(e
) && create
{
120 fd
, e
= syscall
.Create(name
, flag
, syscallMode(perm
))
122 return nil, &PathError
{Op
: "create", Path
: name
, Err
: e
}
128 return nil, &PathError
{Op
: "open", Path
: name
, Err
: e
}
132 if _
, e
= syscall
.Seek(fd
, 0, io
.SeekEnd
); e
!= nil {
133 return nil, &PathError
{Op
: "seek", Path
: name
, Err
: e
}
137 return NewFile(uintptr(fd
), name
), nil
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 ErrClosed 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 {
148 return f
.file
.close()
151 func (file
*file
) close() error
{
152 if file
== nil || file
.fd
== badFd
{
156 if e
:= syscall
.Close(file
.fd
); e
!= nil {
157 err
= &PathError
{Op
: "close", Path
: file
.name
, Err
: e
}
159 file
.fd
= badFd
// so it can't be closed again
161 // no need for a finalizer anymore
162 runtime
.SetFinalizer(file
, nil)
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
) {
170 return nil, ErrInvalid
176 return fileInfoFromStat(d
), nil
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
{
191 var buf
[syscall
.STATFIXLEN
]byte
192 n
, err
:= d
.Marshal(buf
[:])
194 return &PathError
{Op
: "truncate", Path
: f
.name
, Err
: err
}
196 if err
= syscall
.Fwstat(f
.fd
, buf
[:n
]); err
!= nil {
197 return &PathError
{Op
: "truncate", Path
: f
.name
, Err
: err
}
202 const chmodMask
= uint32(syscall
.DMAPPEND | syscall
.DMEXCL | syscall
.DMTMP | ModePerm
)
204 func (f
*File
) chmod(mode FileMode
) error
{
210 odir
, e
:= dirstat(f
)
212 return &PathError
{Op
: "chmod", Path
: f
.name
, Err
: e
}
215 d
.Mode
= odir
.Mode
&^chmodMask |
syscallMode(mode
)&chmodMask
217 var buf
[syscall
.STATFIXLEN
]byte
218 n
, err
:= d
.Marshal(buf
[:])
220 return &PathError
{Op
: "chmod", Path
: f
.name
, Err
: err
}
222 if err
= syscall
.Fwstat(f
.fd
, buf
[:n
]); err
!= nil {
223 return &PathError
{Op
: "chmod", Path
: f
.name
, Err
: err
}
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
{
238 var buf
[syscall
.STATFIXLEN
]byte
239 n
, err
:= d
.Marshal(buf
[:])
241 return &PathError
{Op
: "sync", Path
: f
.name
, Err
: err
}
243 if err
= syscall
.Fwstat(f
.fd
, buf
[:n
]); err
!= nil {
244 return &PathError
{Op
: "sync", Path
: f
.name
, Err
: err
}
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 {
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 {
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
) {
278 return fixCount(syscall
.Write(f
.fd
, b
))
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
) {
289 return fixCount(syscall
.Pwrite(f
.fd
, b
, off
))
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.
302 return syscall
.Seek(f
.fd
, offset
, whence
)
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
{
314 var buf
[syscall
.STATFIXLEN
]byte
315 n
, err
:= d
.Marshal(buf
[:])
317 return &PathError
{Op
: "truncate", Path
: name
, Err
: err
}
319 if err
= syscall
.Wstat(name
, buf
[:n
]); err
!= nil {
320 return &PathError
{Op
: "truncate", Path
: name
, Err
: err
}
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
}
334 // HasPrefix from the strings package.
335 func hasPrefix(s
, prefix
string) bool {
336 return len(s
) >= len(prefix
) && s
[0:len(prefix
)] == prefix
339 func rename(oldname
, newname
string) error
{
340 dirname
:= oldname
[:lastIndex(oldname
, '/')+1]
341 if hasPrefix(newname
, dirname
) {
342 newname
= newname
[len(dirname
):]
344 return &LinkError
{"rename", oldname
, newname
, ErrInvalid
}
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
}
358 buf
:= make([]byte, syscall
.STATFIXLEN
+len(d
.Name
))
359 n
, err
:= d
.Marshal(buf
[:])
361 return &LinkError
{"rename", oldname
, newname
, err
}
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
)
370 if err
= syscall
.Wstat(oldname
, buf
[:n
]); err
!= nil {
371 return &LinkError
{"rename", oldname
, newname
, err
}
376 // See docs in file.go:Chmod.
377 func chmod(name
string, mode FileMode
) error
{
380 odir
, e
:= dirstat(name
)
382 return &PathError
{Op
: "chmod", Path
: name
, Err
: e
}
385 d
.Mode
= odir
.Mode
&^chmodMask |
syscallMode(mode
)&chmodMask
387 var buf
[syscall
.STATFIXLEN
]byte
388 n
, err
:= d
.Marshal(buf
[:])
390 return &PathError
{Op
: "chmod", Path
: name
, Err
: err
}
392 if err
= syscall
.Wstat(name
, buf
[:n
]); err
!= nil {
393 return &PathError
{Op
: "chmod", Path
: name
, Err
: err
}
398 // Chtimes changes the access and modification times of the named
399 // file, similar to the Unix utime() or utimes() functions.
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
{
408 d
.Atime
= uint32(atime
.Unix())
409 d
.Mtime
= uint32(mtime
.Unix())
411 var buf
[syscall
.STATFIXLEN
]byte
412 n
, err
:= d
.Marshal(buf
[:])
414 return &PathError
{Op
: "chtimes", Path
: name
, Err
: err
}
416 if err
= syscall
.Wstat(name
, buf
[:n
]); err
!= nil {
417 return &PathError
{Op
: "chtimes", Path
: name
, Err
: err
}
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
) {
427 if e
:= syscall
.Pipe(p
[0:]); e
!= nil {
428 return nil, nil, NewSyscallError("pipe", e
)
431 return NewFile(uintptr(p
[0]), "|0"), NewFile(uintptr(p
[1]), "|1"), nil
434 // not supported on Plan 9
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
}
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
}
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
}
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.
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
}
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
}
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
{
480 return &PathError
{Op
: "chown", Path
: f
.name
, Err
: syscall
.EPLAN9
}
483 func tempDir() string {
484 dir
:= Getenv("TMPDIR")
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 {
499 if e
:= syscall
.Fchdir(f
.fd
); e
!= nil {
500 return &PathError
{Op
: "chdir", Path
: f
.name
, Err
: e
}
505 // setDeadline sets the read and write deadline.
506 func (f
*File
) setDeadline(time
.Time
) error
{
507 if err
:= f
.checkValid("SetDeadline"); err
!= nil {
510 return poll
.ErrNoDeadline
513 // setReadDeadline sets the read deadline.
514 func (f
*File
) setReadDeadline(time
.Time
) error
{
515 if err
:= f
.checkValid("SetReadDeadline"); err
!= nil {
518 return poll
.ErrNoDeadline
521 // setWriteDeadline sets the write deadline.
522 func (f
*File
) setWriteDeadline(time
.Time
) error
{
523 if err
:= f
.checkValid("SetWriteDeadline"); err
!= nil {
526 return poll
.ErrNoDeadline
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
{
536 return &PathError
{Op
: op
, Path
: f
.name
, Err
: ErrClosed
}
541 type rawConn
struct{}
543 func (c
*rawConn
) Control(f
func(uintptr)) error
{
544 return syscall
.EPLAN9
547 func (c
*rawConn
) Read(f
func(uintptr) bool) error
{
548 return syscall
.EPLAN9
551 func (c
*rawConn
) Write(f
func(uintptr) bool) error
{
552 return syscall
.EPLAN9
555 func newRawConn(file
*File
) (*rawConn
, error
) {
556 return nil, syscall
.EPLAN9
559 func ignoringEINTR(fn
func() error
) error
{