My favorites | Sign in
Logo
go
Project hosting will be READ-ONLY Wednesday at 8am PST due to brief network maintenance.
          
Repository:
Checkout | Browse | Changes | Clones |
 
Changes to /src/pkg/os/file.go
50a1ee9415 vs. 4a3f6bbb5f   Edit
  Compare: vs.   Format:
Revision 4a3f6bbb5f
Go to: 
/src/pkg/os/file.go   50a1ee9415 /src/pkg/os/file.go   4a3f6bbb5f
1 // Copyright 2009 The Go Authors. All rights reserved. 1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // The os package provides a platform-independent interface to operating 5 // The os package provides a platform-independent interface to operating
6 // system functionality. The design is Unix-like. 6 // system functionality. The design is Unix-like.
7 package os 7 package os
8 8
9 import ( 9 import (
10 "syscall"; 10 "syscall";
11 ) 11 )
12 12
13 // Auxiliary information if the File describes a directory 13 // Auxiliary information if the File describes a directory
14 type dirInfo struct { 14 type dirInfo struct {
15 buf []byte; // buffer for directory I/O 15 buf []byte; // buffer for directory I/O
16 nbuf int; // length of buf; return value from Getdirentries 16 nbuf int; // length of buf; return value from Getdirentries
17 bufp int; // location of next record in buf. 17 bufp int; // location of next record in buf.
18 } 18 }
19 19
20 // File represents an open file descriptor. 20 // File represents an open file descriptor.
21 type File struct { 21 type File struct {
22 fd int; 22 fd int;
23 name string; 23 name string;
24 dirinfo *dirInfo; // nil unless directory being read 24 dirinfo *dirInfo; // nil unless directory being read
25 nepipe int; // number of consecutive EPIPE in Write 25 nepipe int; // number of consecutive EPIPE in Write
26 } 26 }
27 27
28 // Fd returns the integer Unix file descriptor referencing the open file. 28 // Fd returns the integer Unix file descriptor referencing the open file.
29 func (file *File) Fd() int { return file.fd } 29 func (file *File) Fd() int { return file.fd }
30 30
31 // Name returns the name of the file as presented to Open. 31 // Name returns the name of the file as presented to Open.
32 func (file *File) Name() string { return file.name } 32 func (file *File) Name() string { return file.name }
33 33
34 // NewFile returns a new File with the given file descriptor and name. 34 // NewFile returns a new File with the given file descriptor and name.
35 func NewFile(fd int, name string) *File { 35 func NewFile(fd int, name string) *File {
36 if fd < 0 { 36 if fd < 0 {
37 return nil 37 return nil
38 } 38 }
39 return &File{fd, name, nil, 0}; 39 return &File{fd, name, nil, 0};
40 } 40 }
41 41
42 // Stdin, Stdout, and Stderr are open Files pointing to the standard input, 42 // Stdin, Stdout, and Stderr are open Files pointing to the standard input,
43 // standard output, and standard error file descriptors. 43 // standard output, and standard error file descriptors.
44 var ( 44 var (
45 Stdin = NewFile(0, "/dev/stdin"); 45 Stdin = NewFile(0, "/dev/stdin");
46 Stdout = NewFile(1, "/dev/stdout"); 46 Stdout = NewFile(1, "/dev/stdout");
47 Stderr = NewFile(2, "/dev/stderr"); 47 Stderr = NewFile(2, "/dev/stderr");
48 ) 48 )
49 49
50 // Flags to Open wrapping those of the underlying system. Not all flags 50 // Flags to Open wrapping those of the underlying system. Not all flags
51 // may be implemented on a given system. 51 // may be implemented on a given system.
52 const ( 52 const (
53 O_RDONLY = syscall.O_RDONLY; // open the file read-only. 53 O_RDONLY = syscall.O_RDONLY; // open the file read-only.
54 O_WRONLY = syscall.O_WRONLY; // open the file write-only. 54 O_WRONLY = syscall.O_WRONLY; // open the file write-only.
55 O_RDWR = syscall.O_RDWR; // open the file read-write. 55 O_RDWR = syscall.O_RDWR; // open the file read-write.
56 O_APPEND = syscall.O_APPEND; // open the file append-only. 56 O_APPEND = syscall.O_APPEND; // open the file append-only.
57 O_ASYNC = syscall.O_ASYNC; // generate a signal when I/O is available. 57 O_ASYNC = syscall.O_ASYNC; // generate a signal when I/O is available.
58 O_CREAT = syscall.O_CREAT; // create a new file if none exists. 58 O_CREAT = syscall.O_CREAT; // create a new file if none exists.
59 O_EXCL = syscall.O_EXCL; // used with O_CREAT, file must not exist 59 O_EXCL = syscall.O_EXCL; // used with O_CREAT, file must not exist
60 O_NOCTTY = syscall.O_NOCTTY; // do not make file the controlling tty. 60 O_NOCTTY = syscall.O_NOCTTY; // do not make file the controlling tty.
61 O_NONBLOCK = syscall.O_NONBLOCK; // open in non-blocking mode. 61 O_NONBLOCK = syscall.O_NONBLOCK; // open in non-blocking mode.
62 O_NDELAY = O_NONBLOCK; // synonym for O_NONBLOCK 62 O_NDELAY = O_NONBLOCK; // synonym for O_NONBLOCK
63 O_SYNC = syscall.O_SYNC; // open for synchronous I/O. 63 O_SYNC = syscall.O_SYNC; // open for synchronous I/O.
64 O_TRUNC = syscall.O_TRUNC; // if possible, truncate file when opened. 64 O_TRUNC = syscall.O_TRUNC; // if possible, truncate file when opened.
65 O_CREATE = O_CREAT; // create a new file if none exists.
65 ) 66 )
66 67
67 // Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.) 68 // Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.)
68 // if applicable. If successful, methods on the returned File can be used for I/O. 69 // if applicable. If successful, methods on the returned File can be used for I/O.
69 // It returns the File and an Error, if any. 70 // It returns the File and an Error, if any.
70 func Open(name string, flag int, perm int) (file *File, err Error) { 71 func Open(name string, flag int, perm int) (file *File, err Error) {
71 r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm); 72 r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm);
72 if e != 0 { 73 if e != 0 {
73 return nil, &PathError{"open", name, Errno(e)} 74 return nil, &PathError{"open", name, Errno(e)}
74 } 75 }
75 76
76 // There's a race here with fork/exec, which we are 77 // There's a race here with fork/exec, which we are
77 // content to live with. See ../syscall/exec.go 78 // content to live with. See ../syscall/exec.go
78 if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported 79 if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
79 syscall.CloseOnExec(r) 80 syscall.CloseOnExec(r)
80 } 81 }
81 82
82 return NewFile(r, name), nil; 83 return NewFile(r, name), nil;
83 } 84 }
84 85
85 // Close closes the File, rendering it unusable for I/O. 86 // Close closes the File, rendering it unusable for I/O.
86 // It returns an Error, if any. 87 // It returns an Error, if any.
87 func (file *File) Close() Error { 88 func (file *File) Close() Error {
88 if file == nil { 89 if file == nil {
89 return EINVAL 90 return EINVAL
90 } 91 }
91 var err Error; 92 var err Error;
92 if e := syscall.Close(file.fd); e != 0 { 93 if e := syscall.Close(file.fd); e != 0 {
93 err = &PathError{"close", file.name, Errno(e)} 94 err = &PathError{"close", file.name, Errno(e)}
94 } 95 }
95 file.fd = -1; // so it can't be closed again 96 file.fd = -1; // so it can't be closed again
96 return err; 97 return err;
97 } 98 }
98 99
99 type eofError int 100 type eofError int
100 101
101 func (eofError) String() string { return "EOF" } 102 func (eofError) String() string { return "EOF" }
102 103
103 // EOF is the Error returned by Read when no more input is available. 104 // EOF is the Error returned by Read when no more input is available.
104 // Functions should return EOF only to signal a graceful end of input. 105 // Functions should return EOF only to signal a graceful end of input.
105 // If the EOF occurs unexpectedly in a structured data stream, 106 // If the EOF occurs unexpectedly in a structured data stream,
106 // the appropriate error is either io.ErrUnexpectedEOF or some other error 107 // the appropriate error is either io.ErrUnexpectedEOF or some other error
107 // giving more detail. 108 // giving more detail.
108 var EOF Error = eofError(0) 109 var EOF Error = eofError(0)
109 110
110 // Read reads up to len(b) bytes from the File. 111 // Read reads up to len(b) bytes from the File.
111 // It returns the number of bytes read and an Error, if any. 112 // It returns the number of bytes read and an Error, if any.
112 // EOF is signaled by a zero count with err set to EOF. 113 // EOF is signaled by a zero count with err set to EOF.
113 func (file *File) Read(b []byte) (n int, err Error) { 114 func (file *File) Read(b []byte) (n int, err Error) {
114 if file == nil { 115 if file == nil {
115 return 0, EINVAL 116 return 0, EINVAL
116 } 117 }
117 n, e := syscall.Read(file.fd, b); 118 n, e := syscall.Read(file.fd, b);
118 if n < 0 { 119 if n < 0 {
119 n = 0 120 n = 0
120 } 121 }
121 if n == 0 && e == 0 { 122 if n == 0 && e == 0 {
122 return 0, EOF 123 return 0, EOF
123 } 124 }
124 if e != 0 { 125 if e != 0 {
125 err = &PathError{"read", file.name, Errno(e)} 126 err = &PathError{"read", file.name, Errno(e)}
126 } 127 }
127 return n, err; 128 return n, err;
128 } 129 }
129 130
130 // ReadAt reads len(b) bytes from the File starting at byte offset off. 131 // ReadAt reads len(b) bytes from the File starting at byte offset off.
131 // It returns the number of bytes read and the Error, if any. 132 // It returns the number of bytes read and the Error, if any.
132 // EOF is signaled by a zero count with err set to EOF. 133 // EOF is signaled by a zero count with err set to EOF.
133 // ReadAt always returns a non-nil Error when n != len(b). 134 // ReadAt always returns a non-nil Error when n != len(b).
134 func (file *File) ReadAt(b []byte, off int64) (n int, err Error) { 135 func (file *File) ReadAt(b []byte, off int64) (n int, err Error) {
135 if file == nil { 136 if file == nil {
136 return 0, EINVAL 137 return 0, EINVAL
137 } 138 }
138 for len(b) > 0 { 139 for len(b) > 0 {
139 m, e := syscall.Pread(file.fd, b, off); 140 m, e := syscall.Pread(file.fd, b, off);
140 n += m; 141 n += m;
141 if e != 0 { 142 if e != 0 {
142 err = &PathError{"read", file.name, Errno(e)}; 143 err = &PathError{"read", file.name, Errno(e)};
143 break; 144 break;
144 } 145 }
145 b = b[m:len(b)]; 146 b = b[m:len(b)];
146 off += int64(m); 147 off += int64(m);
147 } 148 }
148 return; 149 return;
149 } 150 }
150 151
151 // Write writes len(b) bytes to the File. 152 // Write writes len(b) bytes to the File.
152 // It returns the number of bytes written and an Error, if any. 153 // It returns the number of bytes written and an Error, if any.
153 // Write returns a non-nil Error when n != len(b). 154 // Write returns a non-nil Error when n != len(b).
154 func (file *File) Write(b []byte) (n int, err Error) { 155 func (file *File) Write(b []byte) (n int, err Error) {
155 if file == nil { 156 if file == nil {
156 return 0, EINVAL 157 return 0, EINVAL
157 } 158 }
158 n, e := syscall.Write(file.fd, b); 159 n, e := syscall.Write(file.fd, b);
159 if n < 0 { 160 if n < 0 {
160 n = 0 161 n = 0
161 } 162 }
162 if e == syscall.EPIPE { 163 if e == syscall.EPIPE {
163 file.nepipe++; 164 file.nepipe++;
164 if file.nepipe >= 10 { 165 if file.nepipe >= 10 {
165 Exit(syscall.EPIPE) 166 Exit(syscall.EPIPE)
166 } 167 }
167 } else { 168 } else {
168 file.nepipe = 0 169 file.nepipe = 0
169 } 170 }
170 if e != 0 { 171 if e != 0 {
171 err = &PathError{"write", file.name, Errno(e)} 172 err = &PathError{"write", file.name, Errno(e)}
172 } 173 }
173 return n, err; 174 return n, err;
174 } 175 }
175 176
176 // WriteAt writes len(b) bytes to the File starting at byte offset off. 177 // WriteAt writes len(b) bytes to the File starting at byte offset off.
177 // It returns the number of bytes written and an Error, if any. 178 // It returns the number of bytes written and an Error, if any.
178 // WriteAt returns a non-nil Error when n != len(b). 179 // WriteAt returns a non-nil Error when n != len(b).
179 func (file *File) WriteAt(b []byte, off int64) (n int, err Error) { 180 func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
180 if file == nil { 181 if file == nil {
181 return 0, EINVAL 182 return 0, EINVAL
182 } 183 }
183 for len(b) > 0 { 184 for len(b) > 0 {
184 m, e := syscall.Pwrite(file.fd, b, off); 185 m, e := syscall.Pwrite(file.fd, b, off);
185 n += m; 186 n += m;
186 if e != 0 { 187 if e != 0 {
187 err = &PathError{"write", file.name, Errno(e)}; 188 err = &PathError{"write", file.name, Errno(e)};
188 break; 189 break;
189 } 190 }
190 b = b[m:len(b)]; 191 b = b[m:len(b)];
191 off += int64(m); 192 off += int64(m);
192 } 193 }
193 return; 194 return;
194 } 195 }
195 196
196 // Seek sets the offset for the next Read or Write on file to offset, interpreted 197 // Seek sets the offset for the next Read or Write on file to offset, interpreted
197 // according to whence: 0 means relative to the origin of the file, 1 means 198 // according to whence: 0 means relative to the origin of the file, 1 means
198 // relative to the current offset, and 2 means relative to the end. 199 // relative to the current offset, and 2 means relative to the end.
199 // It returns the new offset and an Error, if any. 200 // It returns the new offset and an Error, if any.
200 func (file *File) Seek(offset int64, whence int) (ret int64, err Error) { 201 func (file *File) Seek(offset int64, whence int) (ret int64, err Error) {
201 r, e := syscall.Seek(file.fd, offset, whence); 202 r, e := syscall.Seek(file.fd, offset, whence);
202 if e == 0 && file.dirinfo != nil && r != 0 { 203 if e == 0 && file.dirinfo != nil && r != 0 {
203 e = syscall.EISDIR 204 e = syscall.EISDIR
204 } 205 }
205 if e != 0 { 206 if e != 0 {
206 return 0, &PathError{"seek", file.name, Errno(e)} 207 return 0, &PathError{"seek", file.name, Errno(e)}
207 } 208 }
208 return r, nil; 209 return r, nil;
209 } 210 }
210 211
211 // WriteString is like Write, but writes the contents of string s rather than 212 // WriteString is like Write, but writes the contents of string s rather than
212 // an array of bytes. 213 // an array of bytes.
213 func (file *File) WriteString(s string) (ret int, err Error) { 214 func (file *File) WriteString(s string) (ret int, err Error) {
214 if file == nil { 215 if file == nil {
215 return 0, EINVAL 216 return 0, EINVAL
216 } 217 }
217 b := syscall.StringByteSlice(s); 218 b := syscall.StringByteSlice(s);
218 b = b[0 : len(b)-1]; 219 b = b[0 : len(b)-1];
219 return file.Write(b); 220 return file.Write(b);
220 } 221 }
221 222
222 // Pipe returns a connected pair of Files; reads from r return bytes written to w. 223 // Pipe returns a connected pair of Files; reads from r return bytes written to w.
223 // It returns the files and an Error, if any. 224 // It returns the files and an Error, if any.
224 func Pipe() (r *File, w *File, err Error) { 225 func Pipe() (r *File, w *File, err Error) {
225 var p [2]int; 226 var p [2]int;
226 227
227 // See ../syscall/exec.go for description of lock. 228 // See ../syscall/exec.go for description of lock.
228 syscall.ForkLock.RLock(); 229 syscall.ForkLock.RLock();
229 e := syscall.Pipe(&p); 230 e := syscall.Pipe(&p);
230 if e != 0 { 231 if e != 0 {
231 syscall.ForkLock.RUnlock(); 232 syscall.ForkLock.RUnlock();
232 return nil, nil, NewSyscallError("pipe", e); 233 return nil, nil, NewSyscallError("pipe", e);
233 } 234 }
234 syscall.CloseOnExec(p[0]); 235 syscall.CloseOnExec(p[0]);
235 syscall.CloseOnExec(p[1]); 236 syscall.CloseOnExec(p[1]);
236 syscall.ForkLock.RUnlock(); 237 syscall.ForkLock.RUnlock();
237 238
238 return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil; 239 return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil;
239 } 240 }
240 241
241 // Mkdir creates a new directory with the specified name and permission bits. 242 // Mkdir creates a new directory with the specified name and permission bits.
242 // It returns an error, if any. 243 // It returns an error, if any.
243 func Mkdir(name string, perm int) Error { 244 func Mkdir(name string, perm int) Error {
244 e := syscall.Mkdir(name, perm); 245 e := syscall.Mkdir(name, perm);
245 if e != 0 { 246 if e != 0 {
246 return &PathError{"mkdir", name, Errno(e)} 247 return &PathError{"mkdir", name, Errno(e)}
247 } 248 }
248 return nil; 249 return nil;
249 } 250 }
250 251
251 // Stat returns a Dir structure describing the named file and an error, if any. 252 // Stat returns a Dir structure describing the named file and an error, if any.
252 // If name names a valid symbolic link, the returned Dir describes 253 // If name names a valid symbolic link, the returned Dir describes
253 // the file pointed at by the link and has dir.FollowedSymlink set to true. 254 // the file pointed at by the link and has dir.FollowedSymlink set to true.
254 // If name names an invalid symbolic link, the returned Dir describes 255 // If name names an invalid symbolic link, the returned Dir describes
255 // the link itself and has dir.FollowedSymlink set to false. 256 // the link itself and has dir.FollowedSymlink set to false.
256 func Stat(name string) (dir *Dir, err Error) { 257 func Stat(name string) (dir *Dir, err Error) {
257 var lstat, stat syscall.Stat_t; 258 var lstat, stat syscall.Stat_t;
258 e := syscall.Lstat(name, &lstat); 259 e := syscall.Lstat(name, &lstat);
259 if e != 0 { 260 if e != 0 {
260 return nil, &PathError{"stat", name, Errno(e)} 261 return nil, &PathError{"stat", name, Errno(e)}
261 } 262 }
262 statp := &lstat; 263 statp := &lstat;
263 if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK { 264 if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
264 e := syscall.Stat(name, &stat); 265 e := syscall.Stat(name, &stat);
265 if e == 0 { 266 if e == 0 {
266 statp = &stat 267 statp = &stat
267 } 268 }
268 } 269 }
269 return dirFromStat(name, new(Dir), &lstat, statp), nil; 270 return dirFromStat(name, new(Dir), &lstat, statp), nil;
270 } 271 }
271 272
272 // Stat returns the Dir structure describing file. 273 // Stat returns the Dir structure describing file.
273 // It returns the Dir and an error, if any. 274 // It returns the Dir and an error, if any.
274 func (file *File) Stat() (dir *Dir, err Error) { 275 func (file *File) Stat() (dir *Dir, err Error) {
275 var stat syscall.Stat_t; 276 var stat syscall.Stat_t;
276 e := syscall.Fstat(file.fd, &stat); 277 e := syscall.Fstat(file.fd, &stat);
277 if e != 0 { 278 if e != 0 {
278 return nil, &PathError{"stat", file.name, Errno(e)} 279 return nil, &PathError{"stat", file.name, Errno(e)}
279 } 280 }
280 return dirFromStat(file.name, new(Dir), &stat, &stat), nil; 281 return dirFromStat(file.name, new(Dir), &stat, &stat), nil;
281 } 282 }
282 283
283 // Lstat returns the Dir structure describing the named file and an error, if any. 284 // Lstat returns the Dir structure describing the named file and an error, if any.
284 // If the file is a symbolic link, the returned Dir describes the 285 // If the file is a symbolic link, the returned Dir describes the
285 // symbolic link. Lstat makes no attempt to follow the link. 286 // symbolic link. Lstat makes no attempt to follow the link.
286 func Lstat(name string) (dir *Dir, err Error) { 287 func Lstat(name string) (dir *Dir, err Error) {
287 var stat syscall.Stat_t; 288 var stat syscall.Stat_t;
288 e := syscall.Lstat(name, &stat); 289 e := syscall.Lstat(name, &stat);
289 if e != 0 { 290 if e != 0 {
290 return nil, &PathError{"lstat", name, Errno(e)} 291 return nil, &PathError{"lstat", name, Errno(e)}
291 } 292 }
292 return dirFromStat(name, new(Dir), &stat, &stat), nil; 293 return dirFromStat(name, new(Dir), &stat, &stat), nil;
293 } 294 }
294 295
295 // Readdir reads the contents of the directory associated with file and 296 // Readdir reads the contents of the directory associated with file and
296 // returns an array of up to count Dir structures, as would be returned 297 // returns an array of up to count Dir structures, as would be returned
297 // by Stat, in directory order. Subsequent calls on the same file will yield further Dirs. 298 // by Stat, in directory order. Subsequent calls on the same file will yield further Dirs.
298 // A negative count means to read until EOF. 299 // A negative count means to read until EOF.
299 // Readdir returns the array and an Error, if any. 300 // Readdir returns the array and an Error, if any.
300 func (file *File) Readdir(count int) (dirs []Dir, err Error) { 301 func (file *File) Readdir(count int) (dirs []Dir, err Error) {
301 dirname := file.name; 302 dirname := file.name;
302 if dirname == "" { 303 if dirname == "" {
303 dirname = "." 304 dirname = "."
304 } 305 }
305 dirname += "/"; 306 dirname += "/";
306 names, err1 := file.Readdirnames(count); 307 names, err1 := file.Readdirnames(count);
307 if err1 != nil { 308 if err1 != nil {
308 return nil, err1 309 return nil, err1
309 } 310 }
310 dirs = make([]Dir, len(names)); 311 dirs = make([]Dir, len(names));
311 for i, filename := range names { 312 for i, filename := range names {
312 dirp, err := Lstat(dirname + filename); 313 dirp, err := Lstat(dirname + filename);
313 if dirp == nil || err != nil { 314 if dirp == nil || err != nil {
314 dirs[i].Name = filename // rest is already zeroed out 315 dirs[i].Name = filename // rest is already zeroed out
315 } else { 316 } else {
316 dirs[i] = *dirp 317 dirs[i] = *dirp
317 } 318 }
318 } 319 }
319 return; 320 return;
320 } 321 }
321 322
322 // Chdir changes the current working directory to the named directory. 323 // Chdir changes the current working directory to the named directory.
323 func Chdir(dir string) Error { 324 func Chdir(dir string) Error {
324 if e := syscall.Chdir(dir); e != 0 { 325 if e := syscall.Chdir(dir); e != 0 {
325 return &PathError{"chdir", dir, Errno(e)} 326 return &PathError{"chdir", dir, Errno(e)}
326 } 327 }
327 return nil; 328 return nil;
328 } 329 }
329 330
330 // Chdir changes the current working directory to the file, 331 // Chdir changes the current working directory to the file,
331 // which must be a directory. 332 // which must be a directory.
332 func (f *File) Chdir() Error { 333 func (f *File) Chdir() Error {
333 if e := syscall.Fchdir(f.fd); e != 0 { 334 if e := syscall.Fchdir(f.fd); e != 0 {
334 return &PathError{"chdir", f.name, Errno(e)} 335 return &PathError{"chdir", f.name, Errno(e)}
335 } 336 }
336 return nil; 337 return nil;
337 } 338 }
338 339
339 // Remove removes the named file or directory. 340 // Remove removes the named file or directory.
340 func Remove(name string) Error { 341 func Remove(name string) Error {
341 // System call interface forces us to know 342 // System call interface forces us to know
342 // whether name is a file or directory. 343 // whether name is a file or directory.
343 // Try both: it is cheaper on average than 344 // Try both: it is cheaper on average than
344 // doing a Stat plus the right one. 345 // doing a Stat plus the right one.
345 e := syscall.Unlink(name); 346 e := syscall.Unlink(name);
346 if e == 0 { 347 if e == 0 {
347 return nil 348 return nil
348 } 349 }
349 e1 := syscall.Rmdir(name); 350 e1 := syscall.Rmdir(name);
350 if e1 == 0 { 351 if e1 == 0 {
351 return nil 352 return nil
352 } 353 }
353 354
354 // Both failed: figure out which error to return. 355 // Both failed: figure out which error to return.
355 // OS X and Linux differ on whether unlink(dir) 356 // OS X and Linux differ on whether unlink(dir)
356 // returns EISDIR, so can't use that. However, 357 // returns EISDIR, so can't use that. However,
357 // both agree that rmdir(file) returns ENOTDIR, 358 // both agree that rmdir(file) returns ENOTDIR,
358 // so we can use that to decide which error is real. 359 // so we can use that to decide which error is real.
359 // Rmdir might also return ENOTDIR if given a bad 360 // Rmdir might also return ENOTDIR if given a bad
360 // file path, like /etc/passwd/foo, but in that case, 361 // file path, like /etc/passwd/foo, but in that case,
361 // both errors will be ENOTDIR, so it's okay to 362 // both errors will be ENOTDIR, so it's okay to
362 // use the error from unlink. 363 // use the error from unlink.
363 if e1 != syscall.ENOTDIR { 364 if e1 != syscall.ENOTDIR {
364 e = e1 365 e = e1
365 } 366 }
366 return &PathError{"remove", name, Errno(e)}; 367 return &PathError{"remove", name, Errno(e)};
367 } 368 }
368 369
369 // LinkError records an error during a link or symlink 370 // LinkError records an error during a link or symlink
370 // system call and the paths that caused it. 371 // system call and the paths that caused it.
371 type LinkError struct { 372 type LinkError struct {
372 Op string; 373 Op string;
373 Old string; 374 Old string;
374 New string; 375 New string;
375 Error Error; 376 Error Error;
376 } 377 }
377 378
378 func (e *LinkError) String() string { 379 func (e *LinkError) String() string {
379 return e.Op + " " + e.Old + " " + e.New + ": " + e.Error.String() 380 return e.Op + " " + e.Old + " " + e.New + ": " + e.Error.String()
380 } 381 }
381 382
382 // Link creates a hard link. 383 // Link creates a hard link.
383 func Link(oldname, newname string) Error { 384 func Link(oldname, newname string) Error {
384 e := syscall.Link(oldname, newname); 385 e := syscall.Link(oldname, newname);
385 if e != 0 { 386 if e != 0 {
386 return &LinkError{"link", oldname, newname, Errno(e)} 387 return &LinkError{"link", oldname, newname, Errno(e)}
387 } 388 }
388 return nil; 389 return nil;
389 } 390 }
390 391
391 // Symlink creates a symbolic link. 392 // Symlink creates a symbolic link.
392 func Symlink(oldname, newname string) Error { 393 func Symlink(oldname, newname string) Error {
393 e := syscall.Symlink(oldname, newname); 394 e := syscall.Symlink(oldname, newname);
394 if e != 0 { 395 if e != 0 {
395 return &LinkError{"symlink", oldname, newname, Errno(e)} 396 return &LinkError{"symlink", oldname, newname, Errno(e)}
396 } 397 }
397 return nil; 398 return nil;
398 } 399 }
399 400
400 // Readlink reads the contents of a symbolic link: the destination of 401 // Readlink reads the contents of a symbolic link: the destination of
401 // the link. It returns the contents and an Error, if any. 402 // the link. It returns the contents and an Error, if any.
402 func Readlink(name string) (string, Error) { 403 func Readlink(name string) (string, Error) {
403 for len := 128; ; len *= 2 { 404 for len := 128; ; len *= 2 {
404 b := make([]byte, len); 405 b := make([]byte, len);
405 n, e := syscall.Readlink(name, b); 406 n, e := syscall.Readlink(name, b);
406 if e != 0 { 407 if e != 0 {
407 return "", &PathError{"readlink", name, Errno(e)} 408 return "", &PathError{"readlink", name, Errno(e)}
408 } 409 }
409 if n < len { 410 if n < len {
410 return string(b[0:n]), nil 411 return string(b[0:n]), nil
411 } 412 }
412 } 413 }
413 // Silence 6g. 414 // Silence 6g.
414 return "", nil; 415 return "", nil;
415 } 416 }
416 417
417 // Chmod changes the mode of the named file to mode. 418 // Chmod changes the mode of the named file to mode.
418 // If the file is a symbolic link, it changes the uid and gid of the link's target. 419 // If the file is a symbolic link, it changes the uid and gid of the link's target.
419 func Chmod(name string, mode int) Error { 420 func Chmod(name string, mode int) Error {
420 if e := syscall.Chmod(name, mode); e != 0 { 421 if e := syscall.Chmod(name, mode); e != 0 {
421 return &PathError{"chmod", name, Errno(e)} 422 return &PathError{"chmod", name, Errno(e)}
422 } 423 }
423 return nil; 424 return nil;
424 } 425 }
425 426
426 // Chmod changes the mode of the file to mode. 427 // Chmod changes the mode of the file to mode.
427 func (f *File) Chmod(mode int) Error { 428 func (f *File) Chmod(mode int) Error {
428 if e := syscall.Fchmod(f.fd, mode); e != 0 { 429 if e := syscall.Fchmod(f.fd, mode); e != 0 {
429 return &PathError{"chmod", f.name, Errno(e)} 430 return &PathError{"chmod", f.name, Errno(e)}
430 } 431 }
431 return nil; 432 return nil;
432 } 433 }
433 434
434 // Chown changes the numeric uid and gid of the named file. 435 // Chown changes the numeric uid and gid of the named file.
435 // If the file is a symbolic link, it changes the uid and gid of the link's target. 436 // If the file is a symbolic link, it changes the uid and gid of the link's target.
436 func Chown(name string, uid, gid int) Error { 437 func Chown(name string, uid, gid int) Error {
437 if e := syscall.Chown(name, uid, gid); e != 0 { 438 if e := syscall.Chown(name, uid, gid); e != 0 {
438 return &PathError{"chown", name, Errno(e)} 439 return &PathError{"chown", name, Errno(e)}
439 } 440 }
440 return nil; 441 return nil;
441 } 442 }
442 443
443 // Lchown changes the numeric uid and gid of the named file. 444 // Lchown 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 itself. 445 // If the file is a symbolic link, it changes the uid and gid of the link itself.
445 func Lchown(name string, uid, gid int) Error { 446 func Lchown(name string, uid, gid int) Error {
446 if e := syscall.Lchown(name, uid, gid); e != 0 { 447 if e := syscall.Lchown(name, uid, gid); e != 0 {
447 return &PathError{"lchown", name, Errno(e)} 448 return &PathError{"lchown", name, Errno(e)}
448 } 449 }
449 return nil; 450 return nil;
450 } 451 }
451 452
452 // Chown changes the numeric uid and gid of the named file. 453 // Chown changes the numeric uid and gid of the named file.
453 func (f *File) Chown(uid, gid int) Error { 454 func (f *File) Chown(uid, gid int) Error {
454 if e := syscall.Fchown(f.fd, uid, gid); e != 0 { 455 if e := syscall.Fchown(f.fd, uid, gid); e != 0 {
455 return &PathError{"chown", f.name, Errno(e)} 456 return &PathError{"chown", f.name, Errno(e)}
456 } 457 }
457 return nil; 458 return nil;
458 } 459 }
459 460
460 // Truncate changes the size of the named file. 461 // Truncate changes the size of the named file.
461 // If the file is a symbolic link, it changes the size of the link's target. 462 // If the file is a symbolic link, it changes the size of the link's target.
462 func Truncate(name string, size int64) Error { 463 func Truncate(name string, size int64) Error {
463 if e := syscall.Truncate(name, size); e != 0 { 464 if e := syscall.Truncate(name, size); e != 0 {
464 return &PathError{"truncate", name, Errno(e)} 465 return &PathError{"truncate", name, Errno(e)}
465 } 466 }
466 return nil; 467 return nil;
467 } 468 }
468 469
469 // Truncate changes the size of the file. 470 // Truncate changes the size of the file.
470 // It does not change the I/O offset. 471 // It does not change the I/O offset.
471 func (f *File) Truncate(size int64) Error { 472 func (f *File) Truncate(size int64) Error {
472 if e := syscall.Ftruncate(f.fd, size); e != 0 { 473 if e := syscall.Ftruncate(f.fd, size); e != 0 {
473 return &PathError{"truncate", f.name, Errno(e)} 474 return &PathError{"truncate", f.name, Errno(e)}
474 } 475 }
475 return nil; 476 return nil;
476 } 477 }
Hosted by Google Code