file_plan9.go 12 KB

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