]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/unix/ext/fs.rs
Implement reading and writing atomically at certain offsets
[rust.git] / src / libstd / sys / unix / ext / fs.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Unix-specific extensions to primitives in the `std::fs` module.
12
13 #![stable(feature = "rust1", since = "1.0.0")]
14
15 use fs::{self, Permissions, OpenOptions};
16 use io;
17 use libc;
18 use path::Path;
19 use sys;
20 use sys_common::{FromInner, AsInner, AsInnerMut};
21 use sys::platform::fs::MetadataExt as UnixMetadataExt;
22
23 /// Unix-specific extensions to `File`
24 #[unstable(feature = "file_offset", issue = "35918")]
25 pub trait FileExt {
26     /// Reads a number of bytes starting from a given offset.
27     ///
28     /// Returns the number of bytes read.
29     ///
30     /// The offset is relative to the start of the file and thus independent
31     /// from the current cursor.
32     ///
33     /// The current file cursor is not affected by this function.
34     ///
35     /// Note that similar to `File::read`, it is not an error to return with a
36     /// short read.
37     #[unstable(feature = "file_offset", issue = "35918")]
38     fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
39
40     /// Writes a number of bytes starting from a given offset.
41     ///
42     /// Returns the number of bytes written.
43     ///
44     /// The offset is relative to the start of the file and thus independent
45     /// from the current cursor.
46     ///
47     /// The current file cursor is not affected by this function.
48     ///
49     /// When writing beyond the end of the file, the file is appropiately
50     /// extended and the intermediate bytes are initialized with the value 0.
51     ///
52     /// Note that similar to `File::write`, it is not an error to return a
53     /// short write.
54     #[unstable(feature = "file_offset", issue = "35918")]
55     fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
56 }
57
58 #[unstable(feature = "file_offset", issue = "35918")]
59 impl FileExt for fs::File {
60     fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
61         self.as_inner().read_at(buf, offset)
62     }
63     fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
64         self.as_inner().write_at(buf, offset)
65     }
66 }
67
68 /// Unix-specific extensions to `Permissions`
69 #[stable(feature = "fs_ext", since = "1.1.0")]
70 pub trait PermissionsExt {
71     /// Returns the underlying raw `mode_t` bits that are the standard Unix
72     /// permissions for this file.
73     ///
74     /// # Examples
75     ///
76     /// ```rust,ignore
77     /// use std::fs::File;
78     /// use std::os::unix::fs::PermissionsExt;
79     ///
80     /// let f = try!(File::create("foo.txt"));
81     /// let metadata = try!(f.metadata());
82     /// let permissions = metadata.permissions();
83     ///
84     /// println!("permissions: {}", permissions.mode());
85     /// ```
86     #[stable(feature = "fs_ext", since = "1.1.0")]
87     fn mode(&self) -> u32;
88
89     /// Sets the underlying raw bits for this set of permissions.
90     ///
91     /// # Examples
92     ///
93     /// ```rust,ignore
94     /// use std::fs::File;
95     /// use std::os::unix::fs::PermissionsExt;
96     ///
97     /// let f = try!(File::create("foo.txt"));
98     /// let metadata = try!(f.metadata());
99     /// let mut permissions = metadata.permissions();
100     ///
101     /// permissions.set_mode(0o644); // Read/write for owner and read for others.
102     /// assert_eq!(permissions.mode(), 0o644);
103     /// ```
104     #[stable(feature = "fs_ext", since = "1.1.0")]
105     fn set_mode(&mut self, mode: u32);
106
107     /// Creates a new instance of `Permissions` from the given set of Unix
108     /// permission bits.
109     ///
110     /// # Examples
111     ///
112     /// ```rust,ignore
113     /// use std::fs::Permissions;
114     /// use std::os::unix::fs::PermissionsExt;
115     ///
116     /// // Read/write for owner and read for others.
117     /// let permissions = Permissions::from_mode(0o644);
118     /// assert_eq!(permissions.mode(), 0o644);
119     /// ```
120     #[stable(feature = "fs_ext", since = "1.1.0")]
121     fn from_mode(mode: u32) -> Self;
122 }
123
124 #[stable(feature = "fs_ext", since = "1.1.0")]
125 impl PermissionsExt for Permissions {
126     fn mode(&self) -> u32 {
127         self.as_inner().mode()
128     }
129
130     fn set_mode(&mut self, mode: u32) {
131         *self = Permissions::from_inner(FromInner::from_inner(mode));
132     }
133
134     fn from_mode(mode: u32) -> Permissions {
135         Permissions::from_inner(FromInner::from_inner(mode))
136     }
137 }
138
139 /// Unix-specific extensions to `OpenOptions`
140 #[stable(feature = "fs_ext", since = "1.1.0")]
141 pub trait OpenOptionsExt {
142     /// Sets the mode bits that a new file will be created with.
143     ///
144     /// If a new file is created as part of a `File::open_opts` call then this
145     /// specified `mode` will be used as the permission bits for the new file.
146     /// If no `mode` is set, the default of `0o666` will be used.
147     /// The operating system masks out bits with the systems `umask`, to produce
148     /// the final permissions.
149     ///
150     /// # Examples
151     ///
152     /// ```rust,ignore
153     /// extern crate libc;
154     /// use std::fs::OpenOptions;
155     /// use std::os::unix::fs::OpenOptionsExt;
156     ///
157     /// let mut options = OpenOptions::new();
158     /// options.mode(0o644); // Give read/write for owner and read for others.
159     /// let file = options.open("foo.txt");
160     /// ```
161     #[stable(feature = "fs_ext", since = "1.1.0")]
162     fn mode(&mut self, mode: u32) -> &mut Self;
163
164     /// Pass custom flags to the `flags` agument of `open`.
165     ///
166     /// The bits that define the access mode are masked out with `O_ACCMODE`, to
167     /// ensure they do not interfere with the access mode set by Rusts options.
168     ///
169     /// Custom flags can only set flags, not remove flags set by Rusts options.
170     /// This options overwrites any previously set custom flags.
171     ///
172     /// # Examples
173     ///
174     /// ```rust,ignore
175     /// extern crate libc;
176     /// use std::fs::OpenOptions;
177     /// use std::os::unix::fs::OpenOptionsExt;
178     ///
179     /// let mut options = OpenOptions::new();
180     /// options.write(true);
181     /// if cfg!(unix) {
182     ///     options.custom_flags(libc::O_NOFOLLOW);
183     /// }
184     /// let file = options.open("foo.txt");
185     /// ```
186     #[stable(feature = "open_options_ext", since = "1.10.0")]
187     fn custom_flags(&mut self, flags: i32) -> &mut Self;
188 }
189
190 #[stable(feature = "fs_ext", since = "1.1.0")]
191 impl OpenOptionsExt for OpenOptions {
192     fn mode(&mut self, mode: u32) -> &mut OpenOptions {
193         self.as_inner_mut().mode(mode); self
194     }
195
196     fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
197         self.as_inner_mut().custom_flags(flags); self
198     }
199 }
200
201 // Hm, why are there casts here to the returned type, shouldn't the types always
202 // be the same? Right you are! Turns out, however, on android at least the types
203 // in the raw `stat` structure are not the same as the types being returned. Who
204 // knew!
205 //
206 // As a result to make sure this compiles for all platforms we do the manual
207 // casts and rely on manual lowering to `stat` if the raw type is desired.
208 #[stable(feature = "metadata_ext", since = "1.1.0")]
209 pub trait MetadataExt {
210     #[stable(feature = "metadata_ext", since = "1.1.0")]
211     fn dev(&self) -> u64;
212     #[stable(feature = "metadata_ext", since = "1.1.0")]
213     fn ino(&self) -> u64;
214     #[stable(feature = "metadata_ext", since = "1.1.0")]
215     fn mode(&self) -> u32;
216     #[stable(feature = "metadata_ext", since = "1.1.0")]
217     fn nlink(&self) -> u64;
218     #[stable(feature = "metadata_ext", since = "1.1.0")]
219     fn uid(&self) -> u32;
220     #[stable(feature = "metadata_ext", since = "1.1.0")]
221     fn gid(&self) -> u32;
222     #[stable(feature = "metadata_ext", since = "1.1.0")]
223     fn rdev(&self) -> u64;
224     #[stable(feature = "metadata_ext", since = "1.1.0")]
225     fn size(&self) -> u64;
226     #[stable(feature = "metadata_ext", since = "1.1.0")]
227     fn atime(&self) -> i64;
228     #[stable(feature = "metadata_ext", since = "1.1.0")]
229     fn atime_nsec(&self) -> i64;
230     #[stable(feature = "metadata_ext", since = "1.1.0")]
231     fn mtime(&self) -> i64;
232     #[stable(feature = "metadata_ext", since = "1.1.0")]
233     fn mtime_nsec(&self) -> i64;
234     #[stable(feature = "metadata_ext", since = "1.1.0")]
235     fn ctime(&self) -> i64;
236     #[stable(feature = "metadata_ext", since = "1.1.0")]
237     fn ctime_nsec(&self) -> i64;
238     #[stable(feature = "metadata_ext", since = "1.1.0")]
239     fn blksize(&self) -> u64;
240     #[stable(feature = "metadata_ext", since = "1.1.0")]
241     fn blocks(&self) -> u64;
242 }
243
244 #[stable(feature = "metadata_ext", since = "1.1.0")]
245 impl MetadataExt for fs::Metadata {
246     fn dev(&self) -> u64 { self.st_dev() }
247     fn ino(&self) -> u64 { self.st_ino() }
248     fn mode(&self) -> u32 { self.st_mode() }
249     fn nlink(&self) -> u64 { self.st_nlink() }
250     fn uid(&self) -> u32 { self.st_uid() }
251     fn gid(&self) -> u32 { self.st_gid() }
252     fn rdev(&self) -> u64 { self.st_rdev() }
253     fn size(&self) -> u64 { self.st_size() }
254     fn atime(&self) -> i64 { self.st_atime() }
255     fn atime_nsec(&self) -> i64 { self.st_atime_nsec() }
256     fn mtime(&self) -> i64 { self.st_mtime() }
257     fn mtime_nsec(&self) -> i64 { self.st_mtime_nsec() }
258     fn ctime(&self) -> i64 { self.st_ctime() }
259     fn ctime_nsec(&self) -> i64 { self.st_ctime_nsec() }
260     fn blksize(&self) -> u64 { self.st_blksize() }
261     fn blocks(&self) -> u64 { self.st_blocks() }
262 }
263
264 /// Add special unix types (block/char device, fifo and socket)
265 #[stable(feature = "file_type_ext", since = "1.5.0")]
266 pub trait FileTypeExt {
267     /// Returns whether this file type is a block device.
268     #[stable(feature = "file_type_ext", since = "1.5.0")]
269     fn is_block_device(&self) -> bool;
270     /// Returns whether this file type is a char device.
271     #[stable(feature = "file_type_ext", since = "1.5.0")]
272     fn is_char_device(&self) -> bool;
273     /// Returns whether this file type is a fifo.
274     #[stable(feature = "file_type_ext", since = "1.5.0")]
275     fn is_fifo(&self) -> bool;
276     /// Returns whether this file type is a socket.
277     #[stable(feature = "file_type_ext", since = "1.5.0")]
278     fn is_socket(&self) -> bool;
279 }
280
281 #[stable(feature = "file_type_ext", since = "1.5.0")]
282 impl FileTypeExt for fs::FileType {
283     fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) }
284     fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) }
285     fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) }
286     fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) }
287 }
288
289 /// Unix-specific extension methods for `fs::DirEntry`
290 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
291 pub trait DirEntryExt {
292     /// Returns the underlying `d_ino` field in the contained `dirent`
293     /// structure.
294     ///
295     /// # Examples
296     ///
297     /// ```
298     /// use std::fs;
299     /// use std::os::unix::fs::DirEntryExt;
300     ///
301     /// if let Ok(entries) = fs::read_dir(".") {
302     ///     for entry in entries {
303     ///         if let Ok(entry) = entry {
304     ///             // Here, `entry` is a `DirEntry`.
305     ///             println!("{:?}: {}", entry.file_name(), entry.ino());
306     ///         }
307     ///     }
308     /// }
309     /// ```
310     #[stable(feature = "dir_entry_ext", since = "1.1.0")]
311     fn ino(&self) -> u64;
312 }
313
314 #[stable(feature = "dir_entry_ext", since = "1.1.0")]
315 impl DirEntryExt for fs::DirEntry {
316     fn ino(&self) -> u64 { self.as_inner().ino() }
317 }
318
319 /// Creates a new symbolic link on the filesystem.
320 ///
321 /// The `dst` path will be a symbolic link pointing to the `src` path.
322 ///
323 /// # Note
324 ///
325 /// On Windows, you must specify whether a symbolic link points to a file
326 /// or directory.  Use `os::windows::fs::symlink_file` to create a
327 /// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
328 /// symbolic link to a directory.  Additionally, the process must have
329 /// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
330 /// symbolic link.
331 ///
332 /// # Examples
333 ///
334 /// ```
335 /// use std::os::unix::fs;
336 ///
337 /// # fn foo() -> std::io::Result<()> {
338 /// try!(fs::symlink("a.txt", "b.txt"));
339 /// # Ok(())
340 /// # }
341 /// ```
342 #[stable(feature = "symlink", since = "1.1.0")]
343 pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
344 {
345     sys::fs::symlink(src.as_ref(), dst.as_ref())
346 }
347
348 #[stable(feature = "dir_builder", since = "1.6.0")]
349 /// An extension trait for `fs::DirBuilder` for unix-specific options.
350 pub trait DirBuilderExt {
351     /// Sets the mode to create new directories with. This option defaults to
352     /// 0o777.
353     ///
354     /// # Examples
355     ///
356     /// ```ignore
357     /// use std::fs::DirBuilder;
358     /// use std::os::unix::fs::DirBuilderExt;
359     ///
360     /// let mut builder = DirBuilder::new();
361     /// builder.mode(0o755);
362     /// ```
363     #[stable(feature = "dir_builder", since = "1.6.0")]
364     fn mode(&mut self, mode: u32) -> &mut Self;
365 }
366
367 #[stable(feature = "dir_builder", since = "1.6.0")]
368 impl DirBuilderExt for fs::DirBuilder {
369     fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
370         self.as_inner_mut().set_mode(mode);
371         self
372     }
373 }