1#[cfg(target_family = "unix")]
121use std::io;
122use std::fmt::{self, Debug, Display};
123#[cfg(target_family = "unix")]
124use std::path::Path;
125#[cfg(target_family = "unix")]
126use std::fs::{metadata, symlink_metadata, set_permissions, File};
127use std::iter::FromIterator;
128
129#[cfg(target_family = "unix")]
130use std::os::unix::fs::PermissionsExt;
131
132#[cfg(feature = "serde")]
133use serde::{Serialize, Deserialize};
134
135mod parser;
136pub use parser::ModeParseError;
137
138const S_IFMT: u32 = 0o170000; const S_IFDIR: u32 = 0o040000; const S_IFCHR: u32 = 0o020000; const S_IFBLK: u32 = 0o060000; const S_IFREG: u32 = 0o100000; const S_IFIFO: u32 = 0o010000; const S_IFLNK: u32 = 0o120000; const S_IFSOCK: u32 = 0o140000; const S_ISUID: u32 = 0o4000; const S_ISGID: u32 = 0o2000; const S_ISVTX: u32 = 0o1000; const S_IREAD: u32 = 0o400; const S_IWRITE: u32 = 0o200; const S_IEXEC: u32 = 0o100; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
161pub enum User {
162 Owner,
164 Group,
166 Other,
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
172pub enum FileType {
173 Directory,
174 CharacterDevice,
175 BlockDevice,
176 RegularFile,
177 FIFO,
178 SymbolicLink,
179 Socket,
180}
181
182impl FileType {
183 pub fn from_mode(mode: u32) -> Option<FileType> {
185 use FileType::*;
186 match mode & S_IFMT {
187 S_IFDIR => Some(Directory),
188 S_IFCHR => Some(CharacterDevice),
189 S_IFBLK => Some(BlockDevice),
190 S_IFREG => Some(RegularFile),
191 S_IFIFO => Some(FIFO),
192 S_IFLNK => Some(SymbolicLink),
193 S_IFSOCK => Some(Socket),
194 _ => None
195 }
196 }
197
198 pub fn is_directory(&self) -> bool {
200 *self == FileType::Directory
201 }
202
203 pub fn is_character_device(&self) -> bool {
205 *self == FileType::CharacterDevice
206 }
207
208 pub fn is_block_device(&self) -> bool {
210 *self == FileType::BlockDevice
211 }
212
213 pub fn is_regular_file(&self) -> bool {
215 *self == FileType::RegularFile
216 }
217
218 pub fn is_fifo(&self) -> bool {
220 *self == FileType::FIFO
221 }
222
223 pub fn is_symbolic_link(&self) -> bool {
225 *self == FileType::SymbolicLink
226 }
227
228 pub fn is_socket(&self) -> bool {
230 *self == FileType::Socket
231 }
232
233 pub fn mode(&self) -> Mode {
235 use FileType::*;
236 let mode = match self {
237 Directory => S_IFDIR,
238 CharacterDevice => S_IFCHR,
239 BlockDevice => S_IFBLK,
240 RegularFile => S_IFREG,
241 FIFO => S_IFIFO,
242 SymbolicLink => S_IFLNK,
243 Socket => S_IFSOCK,
244 };
245
246 Mode::new(mode, S_IFMT)
247 }
248}
249
250#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
252pub enum ProtectionBit {
253 Read,
255 Write,
257 Execute,
259 Search,
261}
262
263impl From<ProtectionBit> for Protection {
264 fn from(bit: ProtectionBit) -> Protection {
265 Protection::empty().with_set(bit)
266 }
267}
268
269#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
270enum ExecuteOrSearch {
271 Execute(bool),
272 Search(bool),
273}
274
275#[derive(Debug, Clone)]
277pub struct Protection {
278 read: Option<bool>,
279 write: Option<bool>,
280 execute: Option<ExecuteOrSearch>,
281}
282
283impl Protection {
284 pub fn empty() -> Protection {
286 Protection {
287 read: None,
288 write: None,
289 execute: None,
290 }
291 }
292
293 pub fn all_set() -> Protection {
295 Protection {
296 read: Some(true),
297 write: Some(true),
298 execute: Some(ExecuteOrSearch::Execute(true)),
299 }
300 }
301
302 pub fn all_clear() -> Protection {
304 Protection {
305 read: Some(false),
306 write: Some(false),
307 execute: Some(ExecuteOrSearch::Execute(false)),
308 }
309 }
310
311 pub fn from_mode_user(mode: &Mode, user: User) -> Protection {
313 let mut mask = mode.mask;
314 let mut dir_mask = mode.dir_mask;
315 let mut mode = mode.mode;
316
317 let owner_mask = S_IREAD | S_IWRITE | S_IEXEC;
318
319 let shift = Self::user_shift(user);
320 mode <<= shift;
321 mask <<= shift;
322 dir_mask <<= shift;
323
324 mode &= owner_mask;
325 mask &= owner_mask;
326 dir_mask &= owner_mask;
327
328 let mut ret = Protection::empty();
329
330 if mask & S_IREAD > 0 {
331 ret.read = Some(mode & S_IREAD > 0);
332 }
333
334 if mask & S_IWRITE > 0 {
335 ret.write = Some(mode & S_IWRITE > 0);
336 }
337
338 if mask & S_IEXEC > 0 {
339 if dir_mask & S_IEXEC > 0 {
340 ret.execute = Some(ExecuteOrSearch::Search(mode & S_IEXEC > 0));
341 } else {
342 ret.execute = Some(ExecuteOrSearch::Execute(mode & S_IEXEC > 0));
343 }
344 }
345
346 ret
347 }
348
349 pub fn is_read_set(&self) -> bool {
351 self.read == Some(true)
352 }
353
354 pub fn is_write_set(&self) -> bool {
356 self.write == Some(true)
357 }
358
359 pub fn is_execute_set(&self) -> bool {
361 self.execute == Some(ExecuteOrSearch::Execute(true))
362 }
363
364 pub fn is_search_set(&self) -> bool {
366 self.execute == Some(ExecuteOrSearch::Execute(true)) ||
367 self.execute == Some(ExecuteOrSearch::Search(true))
368 }
369
370 pub fn with_set(mut self, bit: ProtectionBit) -> Protection {
372 self.set(bit);
373 self
374 }
375
376 pub fn with_cleared(mut self, bit: ProtectionBit) -> Protection {
378 self.clear(bit);
379 self
380 }
381
382 pub fn with_forgotten(mut self, bit: ProtectionBit) -> Protection {
384 self.forget(bit);
385 self
386 }
387
388 pub fn set(&mut self, bit: ProtectionBit) {
390 match bit {
391 ProtectionBit::Read => self.read = Some(true),
392 ProtectionBit::Write => self.write = Some(true),
393 ProtectionBit::Execute => self.execute = Some(ExecuteOrSearch::Execute(true)),
394 ProtectionBit::Search => self.execute = Some(ExecuteOrSearch::Search(true)),
395 }
396 }
397
398 pub fn clear(&mut self, bit: ProtectionBit) {
400 match bit {
401 ProtectionBit::Read => self.read = Some(false),
402 ProtectionBit::Write => self.write = Some(false),
403 ProtectionBit::Execute => self.execute = Some(ExecuteOrSearch::Execute(false)),
404 ProtectionBit::Search => self.execute = Some(ExecuteOrSearch::Search(false)),
405 }
406 }
407
408 pub fn forget(&mut self, bit: ProtectionBit) {
410 match bit {
411 ProtectionBit::Read => self.read = None,
412 ProtectionBit::Write => self.write = None,
413 ProtectionBit::Execute | ProtectionBit::Search => self.execute = None,
414 }
415 }
416
417 fn user_shift(user: User) -> u32 {
418 match user {
419 User::Owner => 0,
420 User::Group => 3,
421 User::Other => 6,
422 }
423 }
424
425 pub fn for_user(&self, user: User) -> Mode {
427 let mut mode = Mode::empty();
428
429 if let Some(read) = self.read {
430 if read {
431 mode.mode |= S_IREAD;
432 } else {
433 mode.mode &= !S_IREAD;
434 }
435 mode.mask |= S_IREAD;
436 }
437
438 if let Some(write) = self.write {
439 if write {
440 mode.mode |= S_IWRITE;
441 } else {
442 mode.mode &= !S_IWRITE;
443 }
444 mode.mask |= S_IWRITE;
445 }
446
447 if let Some(execute) = self.execute {
448 match execute {
449 ExecuteOrSearch::Execute(execute) | ExecuteOrSearch::Search(execute) => if execute {
450 mode.mode |= S_IEXEC;
451 } else {
452 mode.mode &= !S_IEXEC;
453 }
454 }
455 mode.mask |= S_IEXEC;
456
457 if let ExecuteOrSearch::Search(_) = execute {
458 mode.dir_mask |= S_IEXEC;
459 }
460 }
461
462 let shift = Self::user_shift(user);
463 mode.mode >>= shift;
464 mode.mask >>= shift;
465 mode.dir_mask >>= shift;
466
467 mode
468 }
469}
470
471#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
473pub enum SpecialBit {
474 SetId,
476 Sticky,
478}
479
480impl From<SpecialBit> for Special {
481 fn from(bit: SpecialBit) -> Special {
482 Special::empty().with_set(bit)
483 }
484}
485
486#[derive(Debug, Clone)]
488pub struct Special {
489 set_id: Option<bool>,
490 sticky: Option<bool>,
491}
492
493impl Special {
494 pub fn empty() -> Special {
495 Special {
496 set_id: None,
497 sticky: None,
498 }
499 }
500
501 pub fn from_mode_user(mode: &Mode, user: User) -> Special {
506 let mut ret = Special::empty();
507
508 match user {
509 User::Owner if mode.mask & S_ISUID > 0 => ret.set_id = Some(mode.mode & S_ISUID > 0),
510 User::Group if mode.mask & S_ISGID > 0 => ret.set_id = Some(mode.mode & S_ISGID > 0),
511 _ => (),
512 }
513
514 if mode.mask & S_ISVTX > 0 {
515 ret.sticky = Some(mode.mode & S_ISVTX > 0);
516 }
517
518 ret
519 }
520
521 pub fn is_set_id_set(&self) -> bool {
526 self.set_id == Some(true)
527 }
528
529 pub fn is_sticky_set(&self) -> bool {
531 self.sticky == Some(true)
532 }
533
534 pub fn with_set(mut self, bit: SpecialBit) -> Special {
536 self.set(bit);
537 self
538 }
539
540 pub fn with_cleared(mut self, bit: SpecialBit) -> Special {
542 self.clear(bit);
543 self
544 }
545
546 pub fn with_forgotten(mut self, bit: SpecialBit) -> Special {
548 self.forget(bit);
549 self
550 }
551
552 pub fn set(&mut self, bit: SpecialBit) {
554 match bit {
555 SpecialBit::SetId => self.set_id = Some(true),
556 SpecialBit::Sticky => self.sticky = Some(true),
557 }
558 }
559
560 pub fn clear(&mut self, bit: SpecialBit) {
562 match bit {
563 SpecialBit::SetId => self.set_id = Some(false),
564 SpecialBit::Sticky => self.sticky = Some(false),
565 }
566 }
567
568 pub fn forget(&mut self, bit: SpecialBit) {
570 match bit {
571 SpecialBit::SetId => self.set_id = None,
572 SpecialBit::Sticky => self.sticky = None,
573 }
574 }
575
576 pub fn for_user(&self, user: User) -> Mode {
581 let mut mode = Mode::empty();
582
583 if let Some(sticky) = self.sticky {
584 if sticky {
585 mode.mode |= S_ISVTX;
586 } else {
587 mode.mode &= !S_ISVTX;
588 }
589 mode.mask |= S_ISVTX;
590 }
591
592 if let Some(set_id) = self.set_id {
593 match user {
594 User::Owner => {
595 if set_id {
596 mode.mode |= S_ISUID;
597 } else {
598 mode.mode &= !S_ISUID;
599 }
600 mode.mask |= S_ISUID;
601 }
602 User::Group => {
603 if set_id {
604 mode.mode |= S_ISGID;
605 } else {
606 mode.mode &= !S_ISGID;
607 }
608 mode.mask |= S_ISGID;
609 }
610 _ => (), }
612 }
613
614 mode
615 }
616}
617
618#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
629#[derive(Clone, PartialEq, Eq, Hash)]
630pub struct Mode {
631 mode: u32,
632 mask: u32,
633 dir_mask: u32,
635}
636
637impl Debug for Mode {
638 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
639 f.debug_struct("Mode")
640 .field("mode", &format_args!("{:06o}", self.mode))
641 .field("mask", &format_args!("{:06o}", self.mask))
642 .field("dirm", &format_args!("{:06o}", self.dir_mask))
643 .finish()
644 }
645}
646
647impl Display for Mode {
648 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
649 use FileType::*;
650 match self.file_type() {
651 Some(Directory) => f.write_str("d")?,
652 Some(CharacterDevice) => f.write_str("c")?,
653 Some(BlockDevice) => f.write_str("b")?,
654 Some(RegularFile) => f.write_str("-")?,
655 Some(FIFO) => f.write_str("p")?,
656 Some(SymbolicLink) => f.write_str("l")?,
657 Some(Socket) => f.write_str("s")?,
658 None => f.write_str("?")?,
659 }
660
661 use User::*;
662 for user in &[Owner, Group, Other] {
663 let special = self.user_special(*user);
664 let protection = self.user_protection(*user);
665
666 if protection.is_read_set() {
667 f.write_str("r")?;
668 } else {
669 f.write_str("-")?;
670 }
671
672 if protection.is_write_set() {
673 f.write_str("w")?;
674 } else {
675 f.write_str("-")?;
676 }
677
678 match user {
679 Owner | Group => match (special.is_set_id_set(), protection.is_execute_set(), protection.is_search_set()) {
680 (true, true, _) => f.write_str("s")?,
681 (true, false, _) => f.write_str("S")?,
682 (false, false, true) => f.write_str("X")?,
683 (false, true, _) => f.write_str("x")?,
684 (false, false, _) => f.write_str("-")?,
685 }
686 Other => match (special.is_sticky_set(), protection.is_execute_set(), protection.is_search_set()) {
687 (true, true, _) => f.write_str("t")?,
688 (true, false, _) => f.write_str("T")?,
689 (false, false, true) => f.write_str("X")?,
690 (false, true, _) => f.write_str("x")?,
691 (false, false, _) => f.write_str("-")?,
692 }
693 }
694 }
695
696 Ok(())
697 }
698}
699
700impl Mode {
701 pub fn new(mode: u32, mask: u32) -> Mode {
704 Mode {
705 mode: mode & (mask | S_IFMT),
706 mask,
707 dir_mask: 0,
708 }
709 }
710
711 pub fn empty() -> Mode {
713 Mode {
714 mode: 0,
715 mask: 0,
716 dir_mask: 0,
717 }
718 }
719
720 #[cfg(target_family = "unix")]
725 pub fn from_path(path: impl AsRef<Path>) -> Result<Mode, io::Error> {
726 Ok(Mode::new(metadata(path.as_ref())?.permissions().mode(), 0o7777 | S_IFMT))
727 }
728
729 #[cfg(target_family = "unix")]
731 pub fn from_path_nofollow(path: impl AsRef<Path>) -> Result<Mode, io::Error> {
732 Ok(Mode::new(symlink_metadata(path.as_ref())?.permissions().mode(), 0o7777 | S_IFMT))
733 }
734
735 #[cfg(target_family = "unix")]
740 pub fn from_file(file: &File) -> Result<Mode, io::Error> {
741 Ok(Mode::new(file.metadata()?.permissions().mode(), 0o7777 | S_IFMT))
742 }
743
744 pub fn mode(&self) -> u32 {
746 self.mode_mask().0
747 }
748
749 pub fn mode_mask(&self) -> (u32, u32) {
754 if let Some(true) = self.file_type().map(|m| m.is_directory()) {
755 (self.mode, self.mask)
756 } else {
757 (self.mode & !self.dir_mask, self.mask & !self.dir_mask)
758 }
759 }
760
761 pub fn file_type(&self) -> Option<FileType> {
763 FileType::from_mode(self.mode)
764 }
765
766 pub fn user_protection(&self, user: User) -> Protection {
768 Protection::from_mode_user(self, user)
769 }
770
771 pub fn user_special(&self, user: User) -> Special {
776 Special::from_mode_user(self, user)
777 }
778
779 pub fn add(&mut self, mode: &Mode) {
781 self.mode |= mode.mode;
782 self.mask |= mode.mask;
783 self.dir_mask |= mode.dir_mask;
784 }
785
786 pub fn sub(&mut self, mode: &Mode) {
788 self.mode &= !mode.mode;
789 self.mask |= mode.mask;
790 self.dir_mask |= mode.dir_mask;
791 }
792
793 pub fn set(&mut self, mode: &Mode) {
795 self.mode &= !mode.mask;
796 self.mode |= mode.mode;
797 self.mask |= mode.mask;
798 self.dir_mask |= mode.dir_mask;
799 }
800
801 pub fn forget(&mut self, mode: &Mode) {
803 self.mode &= !mode.mask;
804 self.mask &= !mode.mask;
805 self.dir_mask &= !mode.dir_mask;
806 }
807
808 pub fn with_file_type(mut self, file_type: FileType) -> Mode {
810 self.set(&file_type.mode());
811 self
812 }
813
814 pub fn with_protection(mut self, user: User, protection: &Protection) -> Mode {
816 self.set(&protection.for_user(user));
817 self
818 }
819
820 pub fn with_special(mut self, user: User, special: &Special) -> Mode {
825 self.set(&special.for_user(user));
826 self
827 }
828
829 pub fn set_file_type(&mut self, file_type: FileType) {
831 self.set(&file_type.mode())
832 }
833
834 pub fn set_protection(&mut self, user: User, protection: &Protection) {
836 self.set(&protection.for_user(user))
837 }
838
839 pub fn set_special(&mut self, user: User, special: &Special) {
844 self.set(&special.for_user(user))
845 }
846
847 pub fn set_str(&mut self, mode_str: &str) -> Result<(), ModeParseError> {
855 self.set_str_umask(mode_str, umask())
856 }
857
858 pub fn set_str_umask(&mut self, mode_str: &str, umask: u32) -> Result<(), ModeParseError> {
860 parser::mode_set_from_str(self, mode_str, umask)
861 }
862
863 pub fn apply_umask(&mut self, mut umask: u32) {
865 umask &= 0o777;
866 self.mode &= !umask;
867 }
868
869 pub fn apply_to(&self, mut mode: u32) -> u32 {
878 let (amode, amask) = if let Some(true) = FileType::from_mode(mode).map(|m| m.is_directory()) {
879 (self.mode, self.mask)
880 } else {
881 (self.mode & !self.dir_mask, self.mask & !self.dir_mask)
882 };
883
884 mode &= !amask;
885 mode | amode
886 }
887
888 #[cfg(target_family = "unix")]
898 pub fn apply_to_path(&self, path: impl AsRef<Path>) -> Result<u32, io::Error> {
899 let file_mode = metadata(path.as_ref())?.permissions().mode();
900 Ok(self.apply_to(file_mode))
901 }
902
903 #[cfg(target_family = "unix")]
905 pub fn apply_to_path_nofollow(&self, path: impl AsRef<Path>) -> Result<u32, io::Error> {
906 let file_mode = symlink_metadata(path.as_ref())?.permissions().mode();
907 Ok(self.apply_to(file_mode))
908 }
909
910 #[cfg(target_family = "unix")]
921 pub fn set_mode_path(&self, path: impl AsRef<Path>) -> Result<u32, io::Error> {
922 let path = path.as_ref();
923 let mut perms = metadata(path)?.permissions();
924 let mode = self.apply_to(perms.mode());
925 perms.set_mode(mode);
926 set_permissions(path, perms)?;
927 Ok(mode)
928 }
929
930 #[cfg(target_family = "unix")]
932 pub fn set_mode_path_nofollow(&self, path: impl AsRef<Path>) -> Result<u32, io::Error> {
933 let path = path.as_ref();
934 let mut perms = symlink_metadata(path)?.permissions();
935 let mode = self.apply_to(perms.mode());
936 perms.set_mode(mode);
937 set_permissions(path, perms)?;
938 Ok(mode)
939 }
940
941 #[cfg(target_family = "unix")]
951 pub fn set_mode_file(&self, file: &File) -> Result<u32, io::Error> {
952 let mut perms = file.metadata()?.permissions();
953 let mode = self.apply_to(perms.mode());
954 perms.set_mode(mode);
955 file.set_permissions(perms)?;
956 Ok(mode)
957 }
958}
959
960impl From<u32> for Mode {
961 fn from(mode: u32) -> Mode {
962 Mode::new(mode, 0o7777)
963 }
964}
965
966impl FromIterator<Mode> for Mode {
967 fn from_iter<I: IntoIterator<Item=Mode>>(iter: I) -> Self {
968 let mut mode = Mode::empty();
969
970 for m in iter {
971 mode.set(&m);
972 }
973
974 mode
975 }
976}
977
978
979#[cfg(target_family = "unix")]
980mod unix {
981 use super::*;
982 use std::error::Error;
983 use std::convert::Infallible;
984
985 #[derive(Debug)]
987 pub enum ModeError {
988 ModeParseError(ModeParseError),
989 IoError(io::Error),
990 }
991
992 impl Display for ModeError {
993 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
994 use ModeError::*;
995 match self {
996 ModeParseError(_) => write!(f, "error parsing file mode string"),
997 IoError(_) => write!(f, "I/O error setting file mode"),
998 }
999 }
1000 }
1001
1002 impl Error for ModeError {
1003 fn source(&self) -> Option<&(dyn Error + 'static)> {
1004 use ModeError::*;
1005 match self {
1006 ModeParseError(err) => Some(err),
1007 IoError(err) => Some(err),
1008 }
1009 }
1010 }
1011
1012 impl From<ModeParseError> for ModeError {
1013 fn from(err: ModeParseError) -> ModeError {
1014 ModeError::ModeParseError(err)
1015 }
1016 }
1017
1018 impl From<io::Error> for ModeError {
1019 fn from(err: io::Error) -> ModeError {
1020 ModeError::IoError(err)
1021 }
1022 }
1023
1024 impl From<Infallible> for ModeError {
1025 fn from(_err: Infallible) -> ModeError {
1026 unreachable!()
1027 }
1028 }
1029
1030 pub enum SetMode<'s> {
1032 Value(Mode),
1033 Str(&'s str),
1034 }
1035
1036 impl<'s, M: Into<Mode>> From<M> for SetMode<'s> {
1037 fn from(val: M) -> SetMode<'s> {
1038 SetMode::Value(val.into())
1039 }
1040 }
1041
1042 impl<'s> From<&'s str> for SetMode<'s> {
1043 fn from(val: &'s str) -> SetMode<'s> {
1044 SetMode::Str(val)
1045 }
1046 }
1047
1048 pub trait ModePath {
1050 fn mode(&self) -> Result<Mode, io::Error>;
1054
1055 fn set_mode<'s, M: Into<SetMode<'s>>>(&self, mode: M) -> Result<u32, ModeError>;
1060 }
1061
1062 impl<T: AsRef<Path>> ModePath for T {
1063 fn mode(&self) -> Result<Mode, io::Error> {
1064 Mode::from_path(self.as_ref())
1065 }
1066
1067 fn set_mode<'s, M: Into<SetMode<'s>>>(&self, mode: M) -> Result<u32, ModeError> {
1068 let mut m = Mode::from_path(self)?; match mode.into() {
1070 SetMode::Value(val) => m.set(&val),
1071 SetMode::Str(val) => m.set_str(val)?, }
1073 Ok(m.set_mode_path(self)?)
1074 }
1075 }
1076
1077 pub trait ModeFile {
1079 fn mode(&self) -> Result<Mode, io::Error>;
1083
1084 fn set_mode<'s, M: Into<SetMode<'s>>>(&self, mode: M) -> Result<u32, ModeError>;
1088 }
1089
1090 impl ModeFile for File {
1091 fn mode(&self) -> Result<Mode, io::Error> {
1092 Mode::from_file(&self)
1093 }
1094
1095 fn set_mode<'s, M: Into<SetMode<'s>>>(&self, mode: M) -> Result<u32, ModeError> {
1096 let mut m = Mode::from_file(self)?; match mode.into() {
1098 SetMode::Value(val) => m.set(&val),
1099 SetMode::Str(val) => m.set_str(val)?, }
1101 Ok(m.set_mode_file(self)?)
1102 }
1103 }
1104
1105 pub fn set_umask(umask: u32) -> u32 {
1109 unsafe {
1110 libc::umask(umask as libc::mode_t) as u32
1111 }
1112 }
1113
1114 pub fn umask() -> u32 {
1118 let m = set_umask(0);
1119 set_umask(m);
1120 m
1121 }
1122}
1123
1124#[cfg(target_family = "unix")]
1125pub use unix::*;
1126
1127#[cfg(not(target_family = "unix"))]
1128mod non_unix {
1129 use std::sync::atomic::{AtomicU32, Ordering};
1130
1131 static UMASK: AtomicU32 = AtomicU32::new(0o002);
1132
1133 pub fn set_umask(umask: u32) -> u32 {
1137 UMASK.swap(umask, Ordering::Release)
1138 }
1139
1140 pub fn umask() -> u32 {
1144 UMASK.load(Ordering::Acquire)
1145 }
1146}
1147
1148#[cfg(not(target_family = "unix"))]
1149pub use non_unix::*;
1150
1151#[cfg(test)]
1152mod tests {
1153 use super::*;
1154 use parking_lot::Mutex;
1155
1156 const UMASK_LOCK: Mutex<()> = parking_lot::const_mutex(());
1157
1158 #[test]
1159 fn test_mode() {
1160 assert_eq!(Mode::new(0o700, 0o700).apply_to(0o412), 0o712);
1161 assert_eq!(Mode::new(0o700, 0o400).apply_to(0o412), 0o412);
1162 assert_eq!(Mode::new(0o000, 0o700).apply_to(0o412), 0o012);
1163 assert_eq!(Mode::new(0o000, 0o111).apply_to(0o412), 0o402);
1164 assert_eq!(Mode::new(0o111, 0o111).apply_to(0o412), 0o513);
1165 assert_eq!(Mode::new(0o777, 0o111).apply_to(0o412), 0o513);
1166 }
1167
1168 #[test]
1169 fn test_protection() {
1170 use ProtectionBit::*;
1171 use User::*;
1172
1173 let mut o_700 = Protection::empty();
1174 o_700.set(Read);
1175 assert!(o_700.is_read_set());
1176 assert!(!o_700.is_write_set());
1177 assert!(!o_700.is_execute_set());
1178
1179 o_700.set(Write);
1180 assert!(o_700.is_read_set());
1181 assert!(o_700.is_write_set());
1182 assert!(!o_700.is_execute_set());
1183
1184 o_700.set(Execute);
1185 assert!(o_700.is_read_set());
1186 assert!(o_700.is_write_set());
1187 assert!(o_700.is_execute_set());
1188
1189 assert_eq!(o_700.for_user(Owner), Mode::new(0o700, 0o700));
1190 assert_eq!(o_700.for_user(Group), Mode::new(0o070, 0o070));
1191 assert_eq!(o_700.for_user(Other), Mode::new(0o007, 0o007));
1192
1193 let mut o_100 = Protection::empty();
1194 o_100.set(Execute);
1195
1196 assert_eq!(o_100.for_user(Owner), Mode::new(0o100, 0o100));
1197 assert_eq!(o_100.for_user(Group), Mode::new(0o010, 0o010));
1198 assert_eq!(o_100.for_user(Other), Mode::new(0o001, 0o001));
1199
1200 let mut o_200 = Protection::empty();
1201 o_200.set(Write);
1202
1203 assert_eq!(o_200.for_user(Owner), Mode::new(0o200, 0o200));
1204 assert_eq!(o_200.for_user(Group), Mode::new(0o020, 0o020));
1205 assert_eq!(o_200.for_user(Other), Mode::new(0o002, 0o002));
1206
1207 let mut o_600 = o_700.clone();
1208 o_600.clear(Execute);
1209 assert_eq!(o_600.for_user(Owner), Mode::new(0o600, 0o700));
1210
1211 let mut o_777 = o_700.for_user(Owner);
1212 o_777.set(&o_700.for_user(Group));
1213 o_777.set(&o_700.for_user(Other));
1214
1215 assert_eq!(o_777, Mode::new(0o777, 0o777));
1216
1217 let mut o_123 = Mode::empty();
1218 o_123.set_protection(Owner, &Protection::empty().with_set(Execute));
1219 o_123.set_protection(Group, &Protection::empty().with_set(Write));
1220 o_123.set_protection(Other, &Protection::empty().with_set(Execute).with_set(Write));
1221
1222 assert_eq!(o_123, Mode::new(0o123, 0o123));
1223
1224 let mut o_102 = o_123;
1225 o_102.set_protection(Group, &Protection::empty().with_cleared(Write));
1226 o_102.set_protection(Other, &Protection::empty().with_cleared(Execute));
1227
1228 assert_eq!(o_102, Mode::new(0o102, 0o123));
1229 }
1230
1231 #[test]
1232 fn test_special() {
1233 use SpecialBit::*;
1234
1235 let mut mode = Mode::empty();
1236 mode.set_special(User::Owner, &SetId.into());
1237 assert_eq!(mode, Mode::new(0o4000, 0o4000));
1238 mode.set_special(User::Group, &SetId.into());
1239 assert_eq!(mode, Mode::new(0o6000, 0o6000));
1240
1241 let mut mode = Mode::empty();
1242 mode.set_special(User::Other, &SetId.into());
1243 assert_eq!(mode, Mode::new(0o0000, 0o0000)); let mut mode = Mode::empty();
1246 mode.set_special(User::Owner, &Sticky.into());
1247 assert_eq!(mode, Mode::new(0o1000, 0o1000));
1248 mode.set_special(User::Group, &Sticky.into());
1249 assert_eq!(mode, Mode::new(0o1000, 0o1000));
1250 mode.set_special(User::Other, &Sticky.into());
1251 assert_eq!(mode, Mode::new(0o1000, 0o1000));
1252
1253 mode.set_special(User::Group, &SetId.into());
1254 assert_eq!(mode, Mode::new(0o3000, 0o3000));
1255
1256 mode.set_special(User::Owner, &SetId.into());
1257 assert_eq!(mode, Mode::new(0o7000, 0o7000));
1258
1259 let mut mode = Mode::empty();
1260 let special = Special::empty();
1261 mode.set_special(User::Owner, &special);
1262 assert_eq!(mode, Mode::new(0o0000, 0o0000));
1263
1264 let special = mode.user_special(User::Owner);
1265 assert!(!special.is_set_id_set());
1266 assert!(!special.is_sticky_set());
1267
1268 mode.set_special(User::Group, &special);
1269 assert_eq!(mode, Mode::new(0o0000, 0o0000));
1270
1271 let special = mode.user_special(User::Owner);
1272 assert!(!special.is_set_id_set());
1273 assert!(!special.is_sticky_set());
1274
1275 let mut mode = Mode::empty();
1276 let mut special = Special::empty();
1277
1278 special.set(SetId);
1279 special.set(Sticky);
1280
1281 mode.set_special(User::Owner, &special);
1282 assert_eq!(mode, Mode::new(0o5000, 0o5000));
1283
1284 let special = mode.user_special(User::Owner);
1285 assert!(special.is_set_id_set());
1286 assert!(special.is_sticky_set());
1287
1288 mode.set_special(User::Group, &special);
1289 assert_eq!(mode, Mode::new(0o7000, 0o7000));
1290
1291 let special = mode.user_special(User::Owner);
1292 assert!(special.is_set_id_set());
1293 assert!(special.is_sticky_set());
1294 }
1295
1296 #[test]
1297 fn test_set_str_umask_symbolic() {
1298 let mut mode = Mode::empty();
1299 mode.set_str("u=rwx,g=rw,o+x").unwrap();
1300 assert_eq!(mode, Mode::new(0o761, 0o771));
1301
1302 let mut mode = Mode::new(0o2777, 0o2777);
1303 mode.set_str_umask("o=t", 0o002).unwrap();
1304 assert_eq!(mode, Mode::new(0o3770, 0o3777)); let mut mode = Mode::new(0o1770, 0o1770);
1307 mode.set_str_umask("g+s", 0o002).unwrap();
1308 assert_eq!(mode, Mode::new(0o3770, 0o3770)); let mut mode = Mode::new(0o0, 0o0);
1311 mode.set_str_umask("=rwx", 0o002).unwrap();
1312 assert_eq!(mode, Mode::new(0o0775, 0o0777)); let mut mode = Mode::new(0o0, 0o0);
1315 mode.set_str_umask("=s", 0o002).unwrap();
1316 assert_eq!(mode, Mode::new(0o6000, 0o6777)); let mut mode = Mode::new(0o0, 0o0);
1319 mode.set_str_umask("=", 0o002).unwrap();
1320 assert_eq!(mode, Mode::new(0o0000, 0o0777)); let mut mode = Mode::new(0o777, 0o7777);
1323 mode.set_str_umask("+w", 0o002).unwrap();
1324 assert_eq!(mode, Mode::new(0o777, 0o7777));
1325
1326 let mut mode = Mode::new(0o000, 0o7777);
1327 mode.set_str_umask("+w", 0o002).unwrap();
1328 assert_eq!(mode, Mode::new(0o220, 0o7777));
1329
1330 let mut mode = Mode::new(0o700, 0o700);
1331 mode.set_str_umask("o=u", 0o002).unwrap();
1332 assert_eq!(mode, Mode::new(0o707, 0o707)); let mut mode = Mode::new(0o100, 0o100);
1335 mode.set_str_umask("o=u", 0o002).unwrap();
1336 assert_eq!(mode, Mode::new(0o101, 0o107)); let mut mode = Mode::new(0o000, 0o000);
1339 mode.set_str_umask("u=rw,og=u", 0o002).unwrap();
1340 assert_eq!(mode, Mode::new(0o666, 0o777)); let mut mode = Mode::new(0o700, 0o700);
1343 mode.set_str_umask("o=u,g=o", 0o002).unwrap();
1344 assert_eq!(mode, Mode::new(0o777, 0o777)); let mut mode = Mode::new(0o604, 0o777); mode.set_str("u+r,g+u").unwrap();
1348 assert_eq!(mode.apply_to(0o664), 0o664); let mut mode = Mode::new(0o664, 0o777); mode.set_str("u+r,g-u").unwrap(); assert_eq!(mode.apply_to(0o664), 0o604); let dir = 0o040664; let file = 0o100664; let mut mode = Mode::empty();
1358 mode.set_str("u+x,g+X").unwrap();
1359
1360 assert_eq!(mode.apply_to(dir), 0o040774);
1361 assert_eq!(mode.apply_to(file), 0o100764);
1362 }
1363
1364 #[test]
1365 fn test_set_str_umask_octal() {
1366 let mut mode = Mode::new(0o000,0o000);
1367 mode.set_str_umask("=777", 0o002).unwrap();
1368 assert_eq!(mode, Mode::new(0o777, 0o7777));
1369
1370 let mut mode = Mode::new(0o000,0o000);
1371 mode.set_str_umask("+777,-111", 0o002).unwrap();
1372 assert_eq!(mode, Mode::new(0o666, 0o7777));
1373
1374 let mut mode = Mode::new(0o000,0o000);
1375 mode.set_str_umask("=0,+7,-1", 0o002).unwrap();
1376 assert_eq!(mode, Mode::new(0o006, 0o7777));
1377
1378 let mut mode = Mode::new(0o000,0o000);
1379 mode.set_str_umask("a=t,ug=s,+7,-1", 0o002).unwrap();
1380 assert_eq!(mode, Mode::new(0o7006, 0o7777));
1381 }
1382
1383 #[test]
1384 fn test_from_str() {
1385 let lock = UMASK_LOCK;
1386 let guard = lock.lock();
1387 let umask = umask();
1388
1389 set_umask(0o002);
1390 let mut mode = Mode::empty();
1391 mode.set_str("=rwx").unwrap();
1392 assert_eq!(mode, Mode::new(0o0775, 0o0777)); set_umask(0o022);
1395 let mut mode = Mode::empty();
1396 mode.set_str("=rwx").unwrap();
1397 assert_eq!(mode, Mode::new(0o0755, 0o0777));
1398
1399 set_umask(0o002);
1400 let mut mode = Mode::empty();
1401 mode.set_str("+w").unwrap();
1402 assert_eq!(mode, Mode::new(0o0220, 0o0222)); set_umask(umask);
1405 drop(guard);
1406 }
1407
1408 #[test]
1409 fn test_file_type() {
1410 assert_eq!(Mode::new(0o040775, 0o177777).file_type(), Some(FileType::Directory)); assert_eq!(Mode::new(0o020666, 0o177777).file_type(), Some(FileType::CharacterDevice)); assert_eq!(Mode::new(0o060660, 0o177777).file_type(), Some(FileType::BlockDevice)); assert_eq!(Mode::new(0o100644, 0o177777).file_type(), Some(FileType::RegularFile)); assert_eq!(Mode::new(0o010664, 0o177777).file_type(), Some(FileType::FIFO));
1416 assert_eq!(Mode::new(0o120777, 0o177777).file_type(), Some(FileType::SymbolicLink)); assert_eq!(Mode::new(0o140777, 0o177777).file_type(), Some(FileType::Socket)); }
1419
1420 #[test]
1421 fn test_apply_to() {
1422 let dir = 0o040664; let file = 0o100664; let mut search = Mode::empty();
1426 search.set_protection(User::Owner, &ProtectionBit::Execute.into());
1427 search.set_protection(User::Group, &ProtectionBit::Search.into());
1428
1429 assert_eq!(search.apply_to(dir), 0o040774);
1430 assert_eq!(search.apply_to(file), 0o100764);
1431 }
1432
1433 #[test]
1434 fn test_to_string() {
1435 assert_eq!(&Mode::new(0o040775, 0o177777).to_string(), "drwxrwxr-x"); assert_eq!(&Mode::new(0o100644, 0o177777).to_string(), "-rw-r--r--"); assert_eq!(&Mode::new(0o104755, 0o177777).to_string(), "-rwsr-xr-x"); assert_eq!(&Mode::new(0o041777, 0o177777).to_string(), "drwxrwxrwt"); assert_eq!(&Mode::new(0o7000, 0o7777).to_string(), "?--S--S--T");
1442
1443 let mut mode = Mode::new(0o7000, 0o7777);
1444 mode.set_file_type(FileType::Directory);
1445 assert_eq!(&mode.to_string(), "d--S--S--T");
1446
1447 let mut mode = Mode::empty();
1448 mode.set_str("u+x,g+X").unwrap();
1449 assert_eq!(&mode.to_string(), "?--x--X---");
1450 }
1451
1452 #[test]
1453 fn test_mode_debug() {
1454 let mode = Mode::new(0o040775, 0o177777); eprintln!("{}", mode);
1456 eprintln!("{:?}", mode);
1457 eprintln!("{:#?}", mode);
1458 }
1459
1460 #[test]
1461 #[cfg(target_family = "unix")]
1462 fn test_set_mode_traits() {
1463 let file = Path::new("LICENSE");
1465 file.set_mode(0o600).unwrap();
1466 assert_eq!(file.set_mode("+r").unwrap() & 0o777, 0o644);
1467
1468 let file = File::open(file).unwrap();
1469 file.set_mode(0o600).unwrap();
1470 assert_eq!(file.set_mode("+r").unwrap() & 0o777, 0o644);
1471 assert_eq!(file.set_mode("g-u").unwrap() & 0o777, 0o604);
1472 assert_eq!(file.set_mode("g+u").unwrap() & 0o777, 0o664);
1473 }
1474}