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.
13 // File represents an open file descriptor.
18 // file is the real representation of *File.
19 // The extra level of indirection ensures that no clients of os
20 // can overwrite this data, which could cause the finalizer
21 // to close the wrong file descriptor.
25 dirinfo
*dirInfo
// nil unless directory being read
28 // Fd returns the integer Plan 9 file descriptor referencing the open file.
29 // The file descriptor is valid only until f.Close is called or f is garbage collected.
30 func (f
*File
) Fd() uintptr {
37 // NewFile returns a new File with the given file descriptor and name.
38 func NewFile(fd
uintptr, name
string) *File
{
43 f
:= &File
{&file
{fd
: fdi
, name
: name
}}
44 runtime
.SetFinalizer(f
.file
, (*file
).close)
48 // Auxiliary information if the File describes a directory
50 buf
[syscall
.STATMAX
]byte // buffer for directory I/O
51 nbuf
int // length of buf; return value from Read
52 bufp
int // location of next record in buf.
55 func epipecheck(file
*File
, e error
) {
58 // DevNull is the name of the operating system's ``null device.''
59 // On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
60 const DevNull
= "/dev/null"
62 // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
63 func syscallMode(i FileMode
) (o
uint32) {
65 if i
&ModeAppend
!= 0 {
68 if i
&ModeExclusive
!= 0 {
71 if i
&ModeTemporary
!= 0 {
77 // OpenFile is the generalized open call; most users will use Open
78 // or Create instead. It opens the named file with specified flag
79 // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
80 // methods on the returned File can be used for I/O.
81 // If there is an error, it will be of type *PathError.
82 func OpenFile(name
string, flag
int, perm FileMode
) (file
*File
, err error
) {
92 if flag
&O_CREATE
== O_CREATE
{
93 flag
= flag
& ^O_CREATE
96 if flag
&O_EXCL
== O_EXCL
{
99 if flag
&O_TRUNC
== O_TRUNC
{
102 // O_APPEND is emulated on Plan 9
103 if flag
&O_APPEND
== O_APPEND
{
104 flag
= flag
&^ O_APPEND
108 if (create
&& trunc
) || excl
{
109 fd
, e
= syscall
.Create(name
, flag
, syscallMode(perm
))
111 fd
, e
= syscall
.Open(name
, flag
)
112 if e
!= nil && create
{
114 fd
, e1
= syscall
.Create(name
, flag
, syscallMode(perm
))
122 return nil, &PathError
{"open", name
, e
}
126 if _
, e
= syscall
.Seek(fd
, 0, SEEK_END
); e
!= nil {
127 return nil, &PathError
{"seek", name
, e
}
131 return NewFile(uintptr(fd
), name
), nil
134 // Close closes the File, rendering it unusable for I/O.
135 // It returns an error, if any.
136 func (f
*File
) Close() error
{
140 return f
.file
.close()
143 func (file
*file
) close() error
{
144 if file
== nil || file
.fd
< 0 {
148 syscall
.ForkLock
.RLock()
149 if e
:= syscall
.Close(file
.fd
); e
!= nil {
150 err
= &PathError
{"close", file
.name
, e
}
152 syscall
.ForkLock
.RUnlock()
153 file
.fd
= -1 // so it can't be closed again
155 // no need for a finalizer anymore
156 runtime
.SetFinalizer(file
, nil)
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() (fi FileInfo
, err error
) {
164 return nil, ErrInvalid
170 return fileInfoFromStat(d
), nil
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
{
185 var buf
[syscall
.STATFIXLEN
]byte
186 n
, err
:= d
.Marshal(buf
[:])
188 return &PathError
{"truncate", f
.name
, err
}
190 if err
= syscall
.Fwstat(f
.fd
, buf
[:n
]); err
!= nil {
191 return &PathError
{"truncate", f
.name
, err
}
196 const chmodMask
= uint32(syscall
.DMAPPEND | syscall
.DMEXCL | syscall
.DMTMP | ModePerm
)
198 // Chmod changes the mode of the file to mode.
199 // If there is an error, it will be of type *PathError.
200 func (f
*File
) Chmod(mode FileMode
) error
{
206 odir
, e
:= dirstat(f
)
208 return &PathError
{"chmod", f
.name
, e
}
211 d
.Mode
= odir
.Mode
&^chmodMask |
syscallMode(mode
)&chmodMask
213 var buf
[syscall
.STATFIXLEN
]byte
214 n
, err
:= d
.Marshal(buf
[:])
216 return &PathError
{"chmod", f
.name
, err
}
218 if err
= syscall
.Fwstat(f
.fd
, buf
[:n
]); err
!= nil {
219 return &PathError
{"chmod", f
.name
, err
}
224 // Sync commits the current contents of the file to stable storage.
225 // Typically, this means flushing the file system's in-memory copy
226 // of recently written data to disk.
227 func (f
*File
) Sync() (err error
) {
234 var buf
[syscall
.STATFIXLEN
]byte
235 n
, err
:= d
.Marshal(buf
[:])
237 return NewSyscallError("fsync", err
)
239 if err
= syscall
.Fwstat(f
.fd
, buf
[:n
]); err
!= nil {
240 return NewSyscallError("fsync", err
)
245 // read reads up to len(b) bytes from the File.
246 // It returns the number of bytes read and an error, if any.
247 func (f
*File
) read(b
[]byte) (n
int, err error
) {
248 return fixCount(syscall
.Read(f
.fd
, b
))
251 // pread reads len(b) bytes from the File starting at byte offset off.
252 // It returns the number of bytes read and the error, if any.
253 // EOF is signaled by a zero count with err set to nil.
254 func (f
*File
) pread(b
[]byte, off
int64) (n
int, err error
) {
255 return fixCount(syscall
.Pread(f
.fd
, b
, off
))
258 // write writes len(b) bytes to the File.
259 // It returns the number of bytes written and an error, if any.
260 // Since Plan 9 preserves message boundaries, never allow
261 // a zero-byte write.
262 func (f
*File
) write(b
[]byte) (n
int, err error
) {
266 return fixCount(syscall
.Write(f
.fd
, b
))
269 // pwrite writes len(b) bytes to the File starting at byte offset off.
270 // It returns the number of bytes written and an error, if any.
271 // Since Plan 9 preserves message boundaries, never allow
272 // a zero-byte write.
273 func (f
*File
) pwrite(b
[]byte, off
int64) (n
int, err error
) {
277 return fixCount(syscall
.Pwrite(f
.fd
, b
, off
))
280 // seek sets the offset for the next Read or Write on file to offset, interpreted
281 // according to whence: 0 means relative to the origin of the file, 1 means
282 // relative to the current offset, and 2 means relative to the end.
283 // It returns the new offset and an error, if any.
284 func (f
*File
) seek(offset
int64, whence
int) (ret
int64, err error
) {
285 return syscall
.Seek(f
.fd
, offset
, whence
)
288 // Truncate changes the size of the named file.
289 // If the file is a symbolic link, it changes the size of the link's target.
290 // If there is an error, it will be of type *PathError.
291 func Truncate(name
string, size
int64) error
{
297 var buf
[syscall
.STATFIXLEN
]byte
298 n
, err
:= d
.Marshal(buf
[:])
300 return &PathError
{"truncate", name
, err
}
302 if err
= syscall
.Wstat(name
, buf
[:n
]); err
!= nil {
303 return &PathError
{"truncate", name
, err
}
308 // Remove removes the named file or directory.
309 // If there is an error, it will be of type *PathError.
310 func Remove(name
string) error
{
311 if e
:= syscall
.Remove(name
); e
!= nil {
312 return &PathError
{"remove", name
, e
}
317 // HasPrefix from the strings package.
318 func hasPrefix(s
, prefix
string) bool {
319 return len(s
) >= len(prefix
) && s
[0:len(prefix
)] == prefix
322 // Variant of LastIndex from the strings package.
323 func lastIndex(s
string, sep
byte) int {
324 for i
:= len(s
) - 1; i
>= 0; i
-- {
332 func rename(oldname
, newname
string) error
{
333 dirname
:= oldname
[:lastIndex(oldname
, '/')+1]
334 if hasPrefix(newname
, dirname
) {
335 newname
= newname
[len(dirname
):]
337 return &LinkError
{"rename", oldname
, newname
, ErrInvalid
}
340 // If newname still contains slashes after removing the oldname
341 // prefix, the rename is cross-directory and must be rejected.
342 // This case is caught by d.Marshal below.
349 buf
:= make([]byte, syscall
.STATFIXLEN
+len(d
.Name
))
350 n
, err
:= d
.Marshal(buf
[:])
352 return &LinkError
{"rename", oldname
, newname
, err
}
354 if err
= syscall
.Wstat(oldname
, buf
[:n
]); err
!= nil {
355 return &LinkError
{"rename", oldname
, newname
, err
}
360 // Chmod changes the mode of the named file to mode.
361 // If the file is a symbolic link, it changes the mode of the link's target.
362 // If there is an error, it will be of type *PathError.
363 func Chmod(name
string, mode FileMode
) error
{
366 odir
, e
:= dirstat(name
)
368 return &PathError
{"chmod", name
, e
}
371 d
.Mode
= odir
.Mode
&^chmodMask |
syscallMode(mode
)&chmodMask
373 var buf
[syscall
.STATFIXLEN
]byte
374 n
, err
:= d
.Marshal(buf
[:])
376 return &PathError
{"chmod", name
, err
}
378 if err
= syscall
.Wstat(name
, buf
[:n
]); err
!= nil {
379 return &PathError
{"chmod", name
, err
}
384 // Chtimes changes the access and modification times of the named
385 // file, similar to the Unix utime() or utimes() functions.
387 // The underlying filesystem may truncate or round the values to a
388 // less precise time unit.
389 // If there is an error, it will be of type *PathError.
390 func Chtimes(name
string, atime time
.Time
, mtime time
.Time
) error
{
394 d
.Atime
= uint32(atime
.Unix())
395 d
.Mtime
= uint32(mtime
.Unix())
397 var buf
[syscall
.STATFIXLEN
]byte
398 n
, err
:= d
.Marshal(buf
[:])
400 return &PathError
{"chtimes", name
, err
}
402 if err
= syscall
.Wstat(name
, buf
[:n
]); err
!= nil {
403 return &PathError
{"chtimes", name
, err
}
408 // Pipe returns a connected pair of Files; reads from r return bytes
409 // written to w. It returns the files and an error, if any.
410 func Pipe() (r
*File
, w
*File
, err error
) {
413 syscall
.ForkLock
.RLock()
414 if e
:= syscall
.Pipe(p
[0:]); e
!= nil {
415 syscall
.ForkLock
.RUnlock()
416 return nil, nil, NewSyscallError("pipe", e
)
418 syscall
.ForkLock
.RUnlock()
420 return NewFile(uintptr(p
[0]), "|0"), NewFile(uintptr(p
[1]), "|1"), nil
423 // not supported on Plan 9
425 // Link creates newname as a hard link to the oldname file.
426 // If there is an error, it will be of type *LinkError.
427 func Link(oldname
, newname
string) error
{
428 return &LinkError
{"link", oldname
, newname
, syscall
.EPLAN9
}
431 // Symlink creates newname as a symbolic link to oldname.
432 // If there is an error, it will be of type *LinkError.
433 func Symlink(oldname
, newname
string) error
{
434 return &LinkError
{"symlink", oldname
, newname
, syscall
.EPLAN9
}
437 // Readlink returns the destination of the named symbolic link.
438 // If there is an error, it will be of type *PathError.
439 func Readlink(name
string) (string, error
) {
440 return "", &PathError
{"readlink", name
, syscall
.EPLAN9
}
443 // Chown changes the numeric uid and gid of the named file.
444 // If the file is a symbolic link, it changes the uid and gid of the link's target.
445 // If there is an error, it will be of type *PathError.
446 func Chown(name
string, uid
, gid
int) error
{
447 return &PathError
{"chown", name
, syscall
.EPLAN9
}
450 // Lchown changes the numeric uid and gid of the named file.
451 // If the file is a symbolic link, it changes the uid and gid of the link itself.
452 // If there is an error, it will be of type *PathError.
453 func Lchown(name
string, uid
, gid
int) error
{
454 return &PathError
{"lchown", name
, syscall
.EPLAN9
}
457 // Chown changes the numeric uid and gid of the named file.
458 // If there is an error, it will be of type *PathError.
459 func (f
*File
) Chown(uid
, gid
int) error
{
463 return &PathError
{"chown", f
.name
, syscall
.EPLAN9
}
466 // TempDir returns the default directory to use for temporary files.
467 func TempDir() string {