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.
14 // fixLongPath is a noop on non-Windows platforms.
15 func fixLongPath(path
string) string {
19 // file is the real representation of *File.
20 // The extra level of indirection ensures that no clients of os
21 // can overwrite this data, which could cause the finalizer
22 // to close the wrong file descriptor.
26 dirinfo
*dirInfo
// nil unless directory being read
29 // Fd returns the integer Plan 9 file descriptor referencing the open file.
30 // The file descriptor is valid only until f.Close is called or f is garbage collected.
31 func (f
*File
) Fd() uintptr {
38 // NewFile returns a new File with the given file descriptor and name.
39 func NewFile(fd
uintptr, name
string) *File
{
44 f
:= &File
{&file
{fd
: fdi
, name
: name
}}
45 runtime
.SetFinalizer(f
.file
, (*file
).close)
49 // Auxiliary information if the File describes a directory
51 buf
[syscall
.STATMAX
]byte // buffer for directory I/O
52 nbuf
int // length of buf; return value from Read
53 bufp
int // location of next record in buf.
56 func epipecheck(file
*File
, e error
) {
59 // DevNull is the name of the operating system's ``null device.''
60 // On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
61 const DevNull
= "/dev/null"
63 // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
64 func syscallMode(i FileMode
) (o
uint32) {
66 if i
&ModeAppend
!= 0 {
69 if i
&ModeExclusive
!= 0 {
72 if i
&ModeTemporary
!= 0 {
78 // OpenFile is the generalized open call; most users will use Open
79 // or Create instead. It opens the named file with specified flag
80 // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
81 // methods on the returned File can be used for I/O.
82 // If there is an error, it will be of type *PathError.
83 func OpenFile(name
string, flag
int, perm FileMode
) (*File
, error
) {
93 if flag
&O_CREATE
== O_CREATE
{
94 flag
= flag
& ^O_CREATE
97 if flag
&O_EXCL
== O_EXCL
{
100 if flag
&O_TRUNC
== O_TRUNC
{
103 // O_APPEND is emulated on Plan 9
104 if flag
&O_APPEND
== O_APPEND
{
105 flag
= flag
&^ O_APPEND
109 if (create
&& trunc
) || excl
{
110 fd
, e
= syscall
.Create(name
, flag
, syscallMode(perm
))
112 fd
, e
= syscall
.Open(name
, flag
)
113 if e
!= nil && create
{
115 fd
, e1
= syscall
.Create(name
, flag
, syscallMode(perm
))
123 return nil, &PathError
{"open", name
, e
}
127 if _
, e
= syscall
.Seek(fd
, 0, io
.SeekEnd
); e
!= nil {
128 return nil, &PathError
{"seek", name
, e
}
132 return NewFile(uintptr(fd
), name
), nil
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 {
141 return f
.file
.close()
144 func (file
*file
) close() error
{
145 if file
== nil || file
.fd
== badFd
{
149 if e
:= syscall
.Close(file
.fd
); e
!= nil {
150 err
= &PathError
{"close", file
.name
, e
}
152 file
.fd
= badFd
// so it can't be closed again
154 // no need for a finalizer anymore
155 runtime
.SetFinalizer(file
, nil)
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
) {
163 return nil, ErrInvalid
169 return fileInfoFromStat(d
), nil
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
{
184 var buf
[syscall
.STATFIXLEN
]byte
185 n
, err
:= d
.Marshal(buf
[:])
187 return &PathError
{"truncate", f
.name
, err
}
189 if err
= syscall
.Fwstat(f
.fd
, buf
[:n
]); err
!= nil {
190 return &PathError
{"truncate", f
.name
, err
}
195 const chmodMask
= uint32(syscall
.DMAPPEND | syscall
.DMEXCL | syscall
.DMTMP | ModePerm
)
197 // Chmod changes the mode of the file to mode.
198 // If there is an error, it will be of type *PathError.
199 func (f
*File
) Chmod(mode FileMode
) error
{
205 odir
, e
:= dirstat(f
)
207 return &PathError
{"chmod", f
.name
, e
}
210 d
.Mode
= odir
.Mode
&^chmodMask |
syscallMode(mode
)&chmodMask
212 var buf
[syscall
.STATFIXLEN
]byte
213 n
, err
:= d
.Marshal(buf
[:])
215 return &PathError
{"chmod", f
.name
, err
}
217 if err
= syscall
.Fwstat(f
.fd
, buf
[:n
]); err
!= nil {
218 return &PathError
{"chmod", f
.name
, err
}
223 // Sync commits the current contents of the file to stable storage.
224 // Typically, this means flushing the file system's in-memory copy
225 // of recently written data to disk.
226 func (f
*File
) Sync() error
{
233 var buf
[syscall
.STATFIXLEN
]byte
234 n
, err
:= d
.Marshal(buf
[:])
236 return NewSyscallError("fsync", err
)
238 if err
= syscall
.Fwstat(f
.fd
, buf
[:n
]); err
!= nil {
239 return NewSyscallError("fsync", err
)
244 // read reads up to len(b) bytes from the File.
245 // It returns the number of bytes read and an error, if any.
246 func (f
*File
) read(b
[]byte) (n
int, err error
) {
247 return fixCount(syscall
.Read(f
.fd
, b
))
250 // pread reads len(b) bytes from the File starting at byte offset off.
251 // It returns the number of bytes read and the error, if any.
252 // EOF is signaled by a zero count with err set to nil.
253 func (f
*File
) pread(b
[]byte, off
int64) (n
int, err error
) {
254 return fixCount(syscall
.Pread(f
.fd
, b
, off
))
257 // write writes len(b) bytes to the File.
258 // It returns the number of bytes written and an error, if any.
259 // Since Plan 9 preserves message boundaries, never allow
260 // a zero-byte write.
261 func (f
*File
) write(b
[]byte) (n
int, err error
) {
265 return fixCount(syscall
.Write(f
.fd
, b
))
268 // pwrite writes len(b) bytes to the File starting at byte offset off.
269 // It returns the number of bytes written and an error, if any.
270 // Since Plan 9 preserves message boundaries, never allow
271 // a zero-byte write.
272 func (f
*File
) pwrite(b
[]byte, off
int64) (n
int, err error
) {
276 return fixCount(syscall
.Pwrite(f
.fd
, b
, off
))
279 // seek sets the offset for the next Read or Write on file to offset, interpreted
280 // according to whence: 0 means relative to the origin of the file, 1 means
281 // relative to the current offset, and 2 means relative to the end.
282 // It returns the new offset and an error, if any.
283 func (f
*File
) seek(offset
int64, whence
int) (ret
int64, err error
) {
284 return syscall
.Seek(f
.fd
, offset
, whence
)
287 // Truncate changes the size of the named file.
288 // If the file is a symbolic link, it changes the size of the link's target.
289 // If there is an error, it will be of type *PathError.
290 func Truncate(name
string, size
int64) error
{
296 var buf
[syscall
.STATFIXLEN
]byte
297 n
, err
:= d
.Marshal(buf
[:])
299 return &PathError
{"truncate", name
, err
}
301 if err
= syscall
.Wstat(name
, buf
[:n
]); err
!= nil {
302 return &PathError
{"truncate", name
, err
}
307 // Remove removes the named file or directory.
308 // If there is an error, it will be of type *PathError.
309 func Remove(name
string) error
{
310 if e
:= syscall
.Remove(name
); e
!= nil {
311 return &PathError
{"remove", name
, e
}
316 // HasPrefix from the strings package.
317 func hasPrefix(s
, prefix
string) bool {
318 return len(s
) >= len(prefix
) && s
[0:len(prefix
)] == prefix
321 // LastIndexByte from the strings package.
322 func lastIndex(s
string, sep
byte) int {
323 for i
:= len(s
) - 1; i
>= 0; i
-- {
331 func rename(oldname
, newname
string) error
{
332 dirname
:= oldname
[:lastIndex(oldname
, '/')+1]
333 if hasPrefix(newname
, dirname
) {
334 newname
= newname
[len(dirname
):]
336 return &LinkError
{"rename", oldname
, newname
, ErrInvalid
}
339 // If newname still contains slashes after removing the oldname
340 // prefix, the rename is cross-directory and must be rejected.
341 if lastIndex(newname
, '/') >= 0 {
342 return &LinkError
{"rename", oldname
, newname
, ErrInvalid
}
350 buf
:= make([]byte, syscall
.STATFIXLEN
+len(d
.Name
))
351 n
, err
:= d
.Marshal(buf
[:])
353 return &LinkError
{"rename", oldname
, newname
, err
}
356 // If newname already exists and is not a directory, rename replaces it.
357 f
, err
:= Stat(dirname
+ newname
)
358 if err
== nil && !f
.IsDir() {
359 Remove(dirname
+ newname
)
362 if err
= syscall
.Wstat(oldname
, buf
[:n
]); err
!= nil {
363 return &LinkError
{"rename", oldname
, newname
, err
}
368 // Chmod changes the mode of the named file to mode.
369 // If the file is a symbolic link, it changes the mode of the link's target.
370 // If there is an error, it will be of type *PathError.
371 func Chmod(name
string, mode FileMode
) error
{
374 odir
, e
:= dirstat(name
)
376 return &PathError
{"chmod", name
, e
}
379 d
.Mode
= odir
.Mode
&^chmodMask |
syscallMode(mode
)&chmodMask
381 var buf
[syscall
.STATFIXLEN
]byte
382 n
, err
:= d
.Marshal(buf
[:])
384 return &PathError
{"chmod", name
, err
}
386 if err
= syscall
.Wstat(name
, buf
[:n
]); err
!= nil {
387 return &PathError
{"chmod", name
, err
}
392 // Chtimes changes the access and modification times of the named
393 // file, similar to the Unix utime() or utimes() functions.
395 // The underlying filesystem may truncate or round the values to a
396 // less precise time unit.
397 // If there is an error, it will be of type *PathError.
398 func Chtimes(name
string, atime time
.Time
, mtime time
.Time
) error
{
402 d
.Atime
= uint32(atime
.Unix())
403 d
.Mtime
= uint32(mtime
.Unix())
405 var buf
[syscall
.STATFIXLEN
]byte
406 n
, err
:= d
.Marshal(buf
[:])
408 return &PathError
{"chtimes", name
, err
}
410 if err
= syscall
.Wstat(name
, buf
[:n
]); err
!= nil {
411 return &PathError
{"chtimes", name
, err
}
416 // Pipe returns a connected pair of Files; reads from r return bytes
417 // written to w. It returns the files and an error, if any.
418 func Pipe() (r
*File
, w
*File
, err error
) {
421 if e
:= syscall
.Pipe(p
[0:]); e
!= nil {
422 return nil, nil, NewSyscallError("pipe", e
)
425 return NewFile(uintptr(p
[0]), "|0"), NewFile(uintptr(p
[1]), "|1"), nil
428 // not supported on Plan 9
430 // Link creates newname as a hard link to the oldname file.
431 // If there is an error, it will be of type *LinkError.
432 func Link(oldname
, newname
string) error
{
433 return &LinkError
{"link", oldname
, newname
, syscall
.EPLAN9
}
436 // Symlink creates newname as a symbolic link to oldname.
437 // If there is an error, it will be of type *LinkError.
438 func Symlink(oldname
, newname
string) error
{
439 return &LinkError
{"symlink", oldname
, newname
, syscall
.EPLAN9
}
442 // Readlink returns the destination of the named symbolic link.
443 // If there is an error, it will be of type *PathError.
444 func Readlink(name
string) (string, error
) {
445 return "", &PathError
{"readlink", name
, syscall
.EPLAN9
}
448 // Chown changes the numeric uid and gid of the named file.
449 // If the file is a symbolic link, it changes the uid and gid of the link's target.
450 // If there is an error, it will be of type *PathError.
451 func Chown(name
string, uid
, gid
int) error
{
452 return &PathError
{"chown", name
, syscall
.EPLAN9
}
455 // Lchown changes the numeric uid and gid of the named file.
456 // If the file is a symbolic link, it changes the uid and gid of the link itself.
457 // If there is an error, it will be of type *PathError.
458 func Lchown(name
string, uid
, gid
int) error
{
459 return &PathError
{"lchown", name
, syscall
.EPLAN9
}
462 // Chown changes the numeric uid and gid of the named file.
463 // If there is an error, it will be of type *PathError.
464 func (f
*File
) Chown(uid
, gid
int) error
{
468 return &PathError
{"chown", f
.name
, syscall
.EPLAN9
}
471 // TempDir returns the default directory to use for temporary files.
472 func TempDir() string {