OSDN Git Service

compiler, libgo: unsafe.{Sizeof,Alignof,Offsetof} return uintptr.
[pf3gnuchains/gcc-fork.git] / libgo / go / os / file_plan9.go
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         "errors"
9         "runtime"
10         "syscall"
11         "time"
12 )
13
14 var ErrPlan9 = errors.New("unimplemented on Plan 9")
15
16 // File represents an open file descriptor.
17 type File struct {
18         *file
19 }
20
21 // file is the real representation of *File.
22 // The extra level of indirection ensures that no clients of os
23 // can overwrite this data, which could cause the finalizer
24 // to close the wrong file descriptor.
25 type file struct {
26         fd      int
27         name    string
28         dirinfo *dirInfo // nil unless directory being read
29 }
30
31 // Fd returns the integer Unix file descriptor referencing the open file.
32 func (f *File) Fd() uintptr {
33         if f == nil {
34                 return ^(uintptr(0))
35         }
36         return uintptr(f.fd)
37 }
38
39 // NewFile returns a new File with the given file descriptor and name.
40 func NewFile(fd uintptr, name string) *File {
41         fdi := int(fd)
42         if fdi < 0 {
43                 return nil
44         }
45         f := &File{&file{fd: fdi, name: name}}
46         runtime.SetFinalizer(f.file, (*file).close)
47         return f
48 }
49
50 // Auxiliary information if the File describes a directory
51 type dirInfo struct {
52         buf  [syscall.STATMAX]byte // buffer for directory I/O
53         nbuf int                   // length of buf; return value from Read
54         bufp int                   // location of next record in buf.
55 }
56
57 func epipecheck(file *File, e error) {
58 }
59
60 // DevNull is the name of the operating system's ``null device.''
61 // On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
62 const DevNull = "/dev/null"
63
64 // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
65 func syscallMode(i FileMode) (o uint32) {
66         o |= uint32(i.Perm())
67         if i&ModeAppend != 0 {
68                 o |= syscall.DMAPPEND
69         }
70         if i&ModeExclusive != 0 {
71                 o |= syscall.DMEXCL
72         }
73         if i&ModeTemporary != 0 {
74                 o |= syscall.DMTMP
75         }
76         return
77 }
78
79 // OpenFile is the generalized open call; most users will use Open
80 // or Create instead.  It opens the named file with specified flag
81 // (O_RDONLY etc.) and perm, (0666 etc.) if applicable.  If successful,
82 // methods on the returned File can be used for I/O.
83 // If there is an error, it will be of type *PathError.
84 func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
85         var (
86                 fd     int
87                 e      error
88                 create bool
89                 excl   bool
90                 trunc  bool
91                 append bool
92         )
93
94         if flag&O_CREATE == O_CREATE {
95                 flag = flag & ^O_CREATE
96                 create = true
97         }
98         if flag&O_EXCL == O_EXCL {
99                 excl = true
100         }
101         if flag&O_TRUNC == O_TRUNC {
102                 trunc = true
103         }
104         // O_APPEND is emulated on Plan 9
105         if flag&O_APPEND == O_APPEND {
106                 flag = flag &^ O_APPEND
107                 append = true
108         }
109
110         syscall.ForkLock.RLock()
111         if (create && trunc) || excl {
112                 fd, e = syscall.Create(name, flag, syscallMode(perm))
113         } else {
114                 fd, e = syscall.Open(name, flag)
115                 if e != nil && create {
116                         var e1 error
117                         fd, e1 = syscall.Create(name, flag, syscallMode(perm))
118                         if e1 == nil {
119                                 e = nil
120                         }
121                 }
122         }
123         syscall.ForkLock.RUnlock()
124
125         if e != nil {
126                 return nil, &PathError{"open", name, e}
127         }
128
129         if append {
130                 if _, e = syscall.Seek(fd, 0, SEEK_END); e != nil {
131                         return nil, &PathError{"seek", name, e}
132                 }
133         }
134
135         return NewFile(uintptr(fd), name), nil
136 }
137
138 // Close closes the File, rendering it unusable for I/O.
139 // It returns an error, if any.
140 func (file *File) Close() error {
141         return file.file.close()
142 }
143
144 func (file *file) close() error {
145         if file == nil || file.fd < 0 {
146                 return ErrInvalid
147         }
148         var err error
149         syscall.ForkLock.RLock()
150         if e := syscall.Close(file.fd); e != nil {
151                 err = &PathError{"close", file.name, e}
152         }
153         syscall.ForkLock.RUnlock()
154         file.fd = -1 // so it can't be closed again
155
156         // no need for a finalizer anymore
157         runtime.SetFinalizer(file, nil)
158         return err
159 }
160
161 // Stat returns the FileInfo structure describing file.
162 // It returns the FileInfo and an error, if any.
163 func (f *File) Stat() (FileInfo, error) {
164         d, err := dirstat(f)
165         if err != nil {
166                 return nil, err
167         }
168         return fileInfoFromStat(d), nil
169 }
170
171 // Truncate changes the size of the file.
172 // It does not change the I/O offset.
173 func (f *File) Truncate(size int64) error {
174         var d Dir
175         d.Null()
176
177         d.Length = uint64(size)
178
179         if e := syscall.Fwstat(f.fd, pdir(nil, &d)); e != nil {
180                 return &PathError{"truncate", f.name, e}
181         }
182         return nil
183 }
184
185 const chmodMask = uint32(syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm)
186
187 // Chmod changes the mode of the file to mode.
188 // If there is an error, it will be of type *PathError.
189 func (f *File) Chmod(mode FileMode) error {
190         var d Dir
191
192         odir, e := dirstat(f)
193         if e != nil {
194                 return &PathError{"chmod", f.name, e}
195         }
196         d.Null()
197         d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
198         if e := syscall.Fwstat(f.fd, pdir(nil, &d)); e != nil {
199                 return &PathError{"chmod", f.name, e}
200         }
201         return nil
202 }
203
204 // Sync commits the current contents of the file to stable storage.
205 // Typically, this means flushing the file system's in-memory copy
206 // of recently written data to disk.
207 func (f *File) Sync() (err error) {
208         if f == nil {
209                 return ErrInvalid
210         }
211
212         var d Dir
213         d.Null()
214
215         if e := syscall.Fwstat(f.fd, pdir(nil, &d)); e != nil {
216                 return NewSyscallError("fsync", e)
217         }
218         return nil
219 }
220
221 // read reads up to len(b) bytes from the File.
222 // It returns the number of bytes read and an error, if any.
223 func (f *File) read(b []byte) (n int, err error) {
224         return syscall.Read(f.fd, b)
225 }
226
227 // pread reads len(b) bytes from the File starting at byte offset off.
228 // It returns the number of bytes read and the error, if any.
229 // EOF is signaled by a zero count with err set to nil.
230 func (f *File) pread(b []byte, off int64) (n int, err error) {
231         return syscall.Pread(f.fd, b, off)
232 }
233
234 // write writes len(b) bytes to the File.
235 // It returns the number of bytes written and an error, if any.
236 func (f *File) write(b []byte) (n int, err error) {
237         return syscall.Write(f.fd, b)
238 }
239
240 // pwrite writes len(b) bytes to the File starting at byte offset off.
241 // It returns the number of bytes written and an error, if any.
242 func (f *File) pwrite(b []byte, off int64) (n int, err error) {
243         return syscall.Pwrite(f.fd, b, off)
244 }
245
246 // seek sets the offset for the next Read or Write on file to offset, interpreted
247 // according to whence: 0 means relative to the origin of the file, 1 means
248 // relative to the current offset, and 2 means relative to the end.
249 // It returns the new offset and an error, if any.
250 func (f *File) seek(offset int64, whence int) (ret int64, err error) {
251         return syscall.Seek(f.fd, offset, whence)
252 }
253
254 // Truncate changes the size of the named file.
255 // If the file is a symbolic link, it changes the size of the link's target.
256 // If there is an error, it will be of type *PathError.
257 func Truncate(name string, size int64) error {
258         var d Dir
259         d.Null()
260
261         d.Length = uint64(size)
262
263         if e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
264                 return &PathError{"truncate", name, e}
265         }
266         return nil
267 }
268
269 // Remove removes the named file or directory.
270 // If there is an error, it will be of type *PathError.
271 func Remove(name string) error {
272         if e := syscall.Remove(name); e != nil {
273                 return &PathError{"remove", name, e}
274         }
275         return nil
276 }
277
278 // Rename renames a file.
279 func Rename(oldname, newname string) error {
280         var d Dir
281         d.Null()
282
283         d.Name = newname
284
285         if e := syscall.Wstat(oldname, pdir(nil, &d)); e != nil {
286                 return &PathError{"rename", oldname, e}
287         }
288         return nil
289 }
290
291 // Chmod changes the mode of the named file to mode.
292 // If there is an error, it will be of type *PathError.
293 func Chmod(name string, mode FileMode) error {
294         var d Dir
295
296         odir, e := dirstat(name)
297         if e != nil {
298                 return &PathError{"chmod", name, e}
299         }
300         d.Null()
301         d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
302         if e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
303                 return &PathError{"chmod", name, e}
304         }
305         return nil
306 }
307
308 // Chtimes changes the access and modification times of the named
309 // file, similar to the Unix utime() or utimes() functions.
310 //
311 // The underlying filesystem may truncate or round the values to a
312 // less precise time unit.
313 func Chtimes(name string, atime time.Time, mtime time.Time) error {
314         var d Dir
315         d.Null()
316
317         d.Atime = uint32(atime.Unix())
318         d.Mtime = uint32(mtime.Unix())
319
320         if e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
321                 return &PathError{"chtimes", name, e}
322         }
323         return nil
324 }
325
326 func Pipe() (r *File, w *File, err error) {
327         var p [2]int
328
329         syscall.ForkLock.RLock()
330         if e := syscall.Pipe(p[0:]); e != nil {
331                 syscall.ForkLock.RUnlock()
332                 return nil, nil, NewSyscallError("pipe", e)
333         }
334         syscall.ForkLock.RUnlock()
335
336         return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
337 }
338
339 // not supported on Plan 9
340
341 // Link creates a hard link.
342 // If there is an error, it will be of type *LinkError.
343 func Link(oldname, newname string) error {
344         return &LinkError{"link", oldname, newname, ErrPlan9}
345 }
346
347 // Symlink creates newname as a symbolic link to oldname.
348 // If there is an error, it will be of type *LinkError.
349 func Symlink(oldname, newname string) error {
350         return &LinkError{"symlink", oldname, newname, ErrPlan9}
351 }
352
353 func Readlink(name string) (string, error) {
354         return "", ErrPlan9
355 }
356
357 func Chown(name string, uid, gid int) error {
358         return ErrPlan9
359 }
360
361 func Lchown(name string, uid, gid int) error {
362         return ErrPlan9
363 }
364
365 func (f *File) Chown(uid, gid int) error {
366         return ErrPlan9
367 }
368
369 // TempDir returns the default directory to use for temporary files.
370 func TempDir() string {
371         return "/tmp"
372 }