Add support for umask
This commit is contained in:
		
							parent
							
								
									05d4c7d7db
								
							
						
					
					
						commit
						87c1c9a8b3
					
				
							
								
								
									
										2
									
								
								deps/sefs
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								deps/sefs
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | ||||
| Subproject commit 41484829326a6bcbd92343f7c1bdcf4acf5a56f4 | ||||
| Subproject commit 8d999ffdf066cc0601c5a726ccfcca75437ced0b | ||||
| @ -53,6 +53,17 @@ impl FileMode { | ||||
|     pub fn has_set_gid(&self) -> bool { | ||||
|         self.contains(FileMode::S_ISGID) | ||||
|     } | ||||
| 
 | ||||
|     /// Umask is FileMode & 0o777, only the file permission bits are used
 | ||||
|     pub fn to_umask(mut self) -> Self { | ||||
|         self.remove(Self::S_ISUID | Self::S_ISGID | Self::S_ISVTX); | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     /// Default umask is 0o022
 | ||||
|     pub fn default_umask() -> Self { | ||||
|         Self::S_IWGRP | Self::S_IWOTH | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn do_fchmodat(fs_path: &FsPath, mode: FileMode) -> Result<()> { | ||||
|  | ||||
| @ -1,12 +1,12 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| pub fn do_mkdirat(fs_path: &FsPath, mode: usize) -> Result<()> { | ||||
|     debug!("mkdirat: fs_path: {:?}, mode: {:#o}", fs_path, mode); | ||||
| pub fn do_mkdirat(fs_path: &FsPath, mode: FileMode) -> Result<()> { | ||||
|     debug!("mkdirat: fs_path: {:?}, mode: {:#o}", fs_path, mode.bits()); | ||||
| 
 | ||||
|     let path = fs_path.to_abs_path()?; | ||||
|     let (dir_path, file_name) = split_path(&path); | ||||
|     let current = current!(); | ||||
|     let inode = { | ||||
|         let current = current!(); | ||||
|         let fs = current.fs().read().unwrap(); | ||||
|         fs.lookup_inode(dir_path)? | ||||
|     }; | ||||
| @ -16,6 +16,7 @@ pub fn do_mkdirat(fs_path: &FsPath, mode: usize) -> Result<()> { | ||||
|     if !inode.allow_write()? { | ||||
|         return_errno!(EPERM, "dir cannot be written"); | ||||
|     } | ||||
|     inode.create(file_name, FileType::Dir, mode as u32)?; | ||||
|     let masked_mode = mode & !current.process().umask(); | ||||
|     inode.create(file_name, FileType::Dir, masked_mode.bits())?; | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| @ -1,16 +1,19 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| pub fn do_openat(fs_path: &FsPath, flags: u32, mode: u32) -> Result<FileDesc> { | ||||
| pub fn do_openat(fs_path: &FsPath, flags: u32, mode: FileMode) -> Result<FileDesc> { | ||||
|     debug!( | ||||
|         "openat: fs_path: {:?}, flags: {:#o}, mode: {:#o}", | ||||
|         fs_path, flags, mode | ||||
|         fs_path, | ||||
|         flags, | ||||
|         mode.bits() | ||||
|     ); | ||||
| 
 | ||||
|     let path = fs_path.to_abs_path()?; | ||||
|     let current = current!(); | ||||
|     let fs = current.fs().read().unwrap(); | ||||
|     let masked_mode = mode & !current.process().umask(); | ||||
| 
 | ||||
|     let file_ref: Arc<dyn File> = fs.open_file(&path, flags, mode)?; | ||||
|     let file_ref: Arc<dyn File> = fs.open_file(&path, flags, masked_mode)?; | ||||
| 
 | ||||
|     let fd = { | ||||
|         let creation_flags = CreationFlags::from_bits_truncate(flags); | ||||
|  | ||||
| @ -44,7 +44,7 @@ impl FsView { | ||||
|     } | ||||
| 
 | ||||
|     /// Open a file on the process. But DO NOT add it to file table.
 | ||||
|     pub fn open_file(&self, path: &str, flags: u32, mode: u32) -> Result<Arc<dyn File>> { | ||||
|     pub fn open_file(&self, path: &str, flags: u32, mode: FileMode) -> Result<Arc<dyn File>> { | ||||
|         let creation_flags = CreationFlags::from_bits_truncate(flags); | ||||
|         let inode = if creation_flags.no_follow_symlink() { | ||||
|             match self.lookup_inode_no_follow(path) { | ||||
| @ -73,7 +73,7 @@ impl FsView { | ||||
|                     if !dir_inode.allow_write()? { | ||||
|                         return_errno!(EPERM, "file cannot be created"); | ||||
|                     } | ||||
|                     dir_inode.create(file_name, FileType::File, mode)? | ||||
|                     dir_inode.create(file_name, FileType::File, mode.bits())? | ||||
|                 } | ||||
|                 Err(e) => return Err(e), | ||||
|             } | ||||
| @ -100,7 +100,7 @@ impl FsView { | ||||
|                     if !dir_inode.allow_write()? { | ||||
|                         return_errno!(EPERM, "file cannot be created"); | ||||
|                     } | ||||
|                     dir_inode.create(file_name, FileType::File, mode)? | ||||
|                     dir_inode.create(file_name, FileType::File, mode.bits())? | ||||
|                 } | ||||
|                 Err(e) => return Err(e), | ||||
|             } | ||||
|  | ||||
| @ -134,7 +134,7 @@ impl INode for HNode { | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn create(&self, name: &str, type_: FileType, mode: u32) -> Result<Arc<dyn INode>> { | ||||
|     fn create(&self, name: &str, type_: FileType, mode: u16) -> Result<Arc<dyn INode>> { | ||||
|         let new_path = self.path.join(name); | ||||
|         if new_path.exists() { | ||||
|             return Err(FsError::EntryExist); | ||||
|  | ||||
| @ -97,25 +97,32 @@ pub fn do_timerfd_gettime(fd: FileDesc, curr_value_ptr: *mut itimerspec_t) -> Re | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| pub fn do_creat(path: *const i8, mode: u32) -> Result<isize> { | ||||
| pub fn do_creat(path: *const i8, mode: u16) -> Result<isize> { | ||||
|     let flags = | ||||
|         AccessMode::O_WRONLY as u32 | (CreationFlags::O_CREAT | CreationFlags::O_TRUNC).bits(); | ||||
|     self::do_open(path, flags, mode) | ||||
| } | ||||
| 
 | ||||
| pub fn do_open(path: *const i8, flags: u32, mode: u32) -> Result<isize> { | ||||
| pub fn do_open(path: *const i8, flags: u32, mode: u16) -> Result<isize> { | ||||
|     self::do_openat(AT_FDCWD, path, flags, mode) | ||||
| } | ||||
| 
 | ||||
| pub fn do_openat(dirfd: i32, path: *const i8, flags: u32, mode: u32) -> Result<isize> { | ||||
| pub fn do_openat(dirfd: i32, path: *const i8, flags: u32, mode: u16) -> Result<isize> { | ||||
|     let path = from_user::clone_cstring_safely(path)? | ||||
|         .to_string_lossy() | ||||
|         .into_owned(); | ||||
|     let fs_path = FsPath::new(&path, dirfd, false)?; | ||||
|     let mode = FileMode::from_bits_truncate(mode); | ||||
|     let fd = file_ops::do_openat(&fs_path, flags, mode)?; | ||||
|     Ok(fd as isize) | ||||
| } | ||||
| 
 | ||||
| pub fn do_umask(mask: u16) -> Result<isize> { | ||||
|     let new_mask = FileMode::from_bits_truncate(mask).to_umask(); | ||||
|     let old_mask = current!().process().set_umask(new_mask); | ||||
|     Ok(old_mask.bits() as isize) | ||||
| } | ||||
| 
 | ||||
| pub fn do_close(fd: FileDesc) -> Result<isize> { | ||||
|     file_ops::do_close(fd)?; | ||||
|     Ok(0) | ||||
| @ -414,15 +421,16 @@ pub fn do_renameat( | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| pub fn do_mkdir(path: *const i8, mode: usize) -> Result<isize> { | ||||
| pub fn do_mkdir(path: *const i8, mode: u16) -> Result<isize> { | ||||
|     self::do_mkdirat(AT_FDCWD, path, mode) | ||||
| } | ||||
| 
 | ||||
| pub fn do_mkdirat(dirfd: i32, path: *const i8, mode: usize) -> Result<isize> { | ||||
| pub fn do_mkdirat(dirfd: i32, path: *const i8, mode: u16) -> Result<isize> { | ||||
|     let path = from_user::clone_cstring_safely(path)? | ||||
|         .to_string_lossy() | ||||
|         .into_owned(); | ||||
|     let fs_path = FsPath::new(&path, dirfd, false)?; | ||||
|     let mode = FileMode::from_bits_truncate(mode); | ||||
|     file_ops::do_mkdirat(&fs_path, mode)?; | ||||
|     Ok(0) | ||||
| } | ||||
|  | ||||
| @ -3,8 +3,8 @@ use super::endpoint::{end_pair, Endpoint, RelayNotifier}; | ||||
| use super::*; | ||||
| use events::{Event, EventFilter, Notifier, Observer}; | ||||
| use fs::channel::Channel; | ||||
| use fs::CreationFlags; | ||||
| use fs::IoEvents; | ||||
| use fs::{CreationFlags, FileMode}; | ||||
| use std::fmt; | ||||
| use std::sync::atomic::{AtomicBool, Ordering}; | ||||
| use std::sync::Arc; | ||||
| @ -75,8 +75,11 @@ impl Stream { | ||||
|             let corresponding_inode_num = { | ||||
|                 let current = current!(); | ||||
|                 let fs = current.fs().read().unwrap(); | ||||
|                 let file_ref = | ||||
|                     fs.open_file(path.path_str(), CreationFlags::O_CREAT.bits(), 0o777)?; | ||||
|                 let file_ref = fs.open_file( | ||||
|                     path.path_str(), | ||||
|                     CreationFlags::O_CREAT.bits(), | ||||
|                     FileMode::from_bits(0o777).unwrap(), | ||||
|                 )?; | ||||
|                 file_ref.metadata()?.inode | ||||
|             }; | ||||
|             *inode_num = Some(corresponding_inode_num); | ||||
|  | ||||
| @ -10,7 +10,7 @@ use super::task::Task; | ||||
| use super::thread::{ThreadId, ThreadName}; | ||||
| use super::{table, task, ProcessRef, ThreadRef}; | ||||
| use crate::fs::{ | ||||
|     CreationFlags, File, FileDesc, FileTable, FsView, HostStdioFds, StdinFile, StdoutFile, | ||||
|     CreationFlags, File, FileDesc, FileMode, FileTable, FsView, HostStdioFds, StdinFile, StdoutFile, | ||||
| }; | ||||
| use crate::prelude::*; | ||||
| use crate::vm::ProcessVM; | ||||
| @ -285,6 +285,7 @@ fn new_process_common( | ||||
|         process_builder | ||||
|             .vm(vm_ref) | ||||
|             .exec_path(&elf_path) | ||||
|             .umask(parent.umask()) | ||||
|             .parent(parent) | ||||
|             .task(task) | ||||
|             .sched(sched_ref) | ||||
| @ -339,12 +340,11 @@ fn init_files( | ||||
|                     oflag, | ||||
|                     fd, | ||||
|                 } => { | ||||
|                     let file_ref = | ||||
|                         current_ref | ||||
|                             .fs() | ||||
|                             .read() | ||||
|                             .unwrap() | ||||
|                             .open_file(path.as_str(), oflag, mode)?; | ||||
|                     let file_ref = current_ref.fs().read().unwrap().open_file( | ||||
|                         path.as_str(), | ||||
|                         oflag, | ||||
|                         FileMode::from_bits_truncate(mode as u16), | ||||
|                     )?; | ||||
|                     let creation_flags = CreationFlags::from_bits_truncate(oflag); | ||||
|                     cloned_file_table.put_at(fd, file_ref, creation_flags.must_close_on_spawn()); | ||||
|                 } | ||||
|  | ||||
| @ -5,6 +5,7 @@ use super::super::{ | ||||
|     SchedAgentRef, | ||||
| }; | ||||
| use super::{Process, ProcessInner}; | ||||
| use crate::fs::FileMode; | ||||
| use crate::prelude::*; | ||||
| use crate::signal::{SigDispositions, SigQueues, SigSet}; | ||||
| 
 | ||||
| @ -16,6 +17,7 @@ pub struct ProcessBuilder { | ||||
|     vm: Option<ProcessVMRef>, | ||||
|     // Optional fields, which have reasonable default values
 | ||||
|     exec_path: Option<String>, | ||||
|     umask: Option<FileMode>, | ||||
|     parent: Option<ProcessRef>, | ||||
|     no_parent: bool, | ||||
|     sig_dispositions: Option<SigDispositions>, | ||||
| @ -29,6 +31,7 @@ impl ProcessBuilder { | ||||
|             thread_builder: Some(thread_builder), | ||||
|             vm: None, | ||||
|             exec_path: None, | ||||
|             umask: None, | ||||
|             parent: None, | ||||
|             no_parent: false, | ||||
|             sig_dispositions: None, | ||||
| @ -45,6 +48,11 @@ impl ProcessBuilder { | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     pub fn umask(mut self, umask: FileMode) -> Self { | ||||
|         self.umask = Some(umask); | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     pub fn parent(mut self, parent: ProcessRef) -> Self { | ||||
|         self.parent = Some(parent); | ||||
|         self | ||||
| @ -108,6 +116,7 @@ impl ProcessBuilder { | ||||
|         // Build a new process
 | ||||
|         let new_process = { | ||||
|             let exec_path = self.exec_path.take().unwrap_or_default(); | ||||
|             let umask = RwLock::new(self.umask.unwrap_or(FileMode::default_umask())); | ||||
|             let parent = self.parent.take().map(|parent| RwLock::new(parent)); | ||||
|             let inner = SgxMutex::new(ProcessInner::new()); | ||||
|             let sig_dispositions = RwLock::new(self.sig_dispositions.unwrap_or_default()); | ||||
| @ -116,6 +125,7 @@ impl ProcessBuilder { | ||||
|             Arc::new(Process { | ||||
|                 pid, | ||||
|                 exec_path, | ||||
|                 umask, | ||||
|                 parent, | ||||
|                 inner, | ||||
|                 sig_dispositions, | ||||
|  | ||||
| @ -2,6 +2,7 @@ use std::fmt; | ||||
| 
 | ||||
| use super::wait::WaitQueue; | ||||
| use super::{ForcedExitStatus, ProcessRef, TermStatus, ThreadRef}; | ||||
| use crate::fs::FileMode; | ||||
| use crate::prelude::*; | ||||
| use crate::signal::{SigDispositions, SigNum, SigQueues}; | ||||
| 
 | ||||
| @ -18,6 +19,7 @@ pub struct Process { | ||||
|     // Mutable info
 | ||||
|     parent: Option<RwLock<ProcessRef>>, | ||||
|     inner: SgxMutex<ProcessInner>, | ||||
|     umask: RwLock<FileMode>, | ||||
|     // Signal
 | ||||
|     sig_dispositions: RwLock<SigDispositions>, | ||||
|     sig_queues: RwLock<SigQueues>, | ||||
| @ -99,6 +101,19 @@ impl Process { | ||||
|         &self.exec_path | ||||
|     } | ||||
| 
 | ||||
|     /// Get the file mode creation mask
 | ||||
|     pub fn umask(&self) -> FileMode { | ||||
|         self.umask.read().unwrap().clone() | ||||
|     } | ||||
| 
 | ||||
|     /// Set the file mode creation mask, return the previous value
 | ||||
|     pub fn set_umask(&self, new_mask: FileMode) -> FileMode { | ||||
|         let mut mask = self.umask.write().unwrap(); | ||||
|         let old_mask = mask.clone(); | ||||
|         *mask = new_mask; | ||||
|         old_mask | ||||
|     } | ||||
| 
 | ||||
|     /// Get the signal queues for process-directed signals.
 | ||||
|     pub fn sig_queues(&self) -> &RwLock<SigQueues> { | ||||
|         &self.sig_queues | ||||
|  | ||||
| @ -29,8 +29,9 @@ use crate::fs::{ | ||||
|     do_lseek, do_lstat, do_mkdir, do_mkdirat, do_mount_rootfs, do_open, do_openat, do_pipe, | ||||
|     do_pipe2, do_pread, do_pwrite, do_read, do_readlink, do_readlinkat, do_readv, do_rename, | ||||
|     do_renameat, do_rmdir, do_sendfile, do_stat, do_statfs, do_symlink, do_symlinkat, do_sync, | ||||
|     do_timerfd_create, do_timerfd_gettime, do_timerfd_settime, do_truncate, do_unlink, do_unlinkat, | ||||
|     do_write, do_writev, iovec_t, AsTimer, File, FileDesc, FileRef, HostStdioFds, Stat, Statfs, | ||||
|     do_timerfd_create, do_timerfd_gettime, do_timerfd_settime, do_truncate, do_umask, do_unlink, | ||||
|     do_unlinkat, do_write, do_writev, iovec_t, AsTimer, File, FileDesc, FileRef, HostStdioFds, | ||||
|     Stat, Statfs, | ||||
| }; | ||||
| use crate::interrupt::{do_handle_interrupt, sgx_interrupt_info_t}; | ||||
| use crate::misc::{resource_t, rlimit_t, sysinfo_t, utsname_t}; | ||||
| @ -89,7 +90,7 @@ macro_rules! process_syscall_table_with_callback { | ||||
|             // TODO: Unify the use of C types. For example, u8 or i8 or char_c for C string?
 | ||||
|             (Read = 0) => do_read(fd: FileDesc, buf: *mut u8, size: usize), | ||||
|             (Write = 1) => do_write(fd: FileDesc, buf: *const u8, size: usize), | ||||
|             (Open = 2) => do_open(path: *const i8, flags: u32, mode: u32), | ||||
|             (Open = 2) => do_open(path: *const i8, flags: u32, mode: u16), | ||||
|             (Close = 3) => do_close(fd: FileDesc), | ||||
|             (Stat = 4) => do_stat(path: *const i8, stat_buf: *mut Stat), | ||||
|             (Fstat = 5) => do_fstat(fd: FileDesc, stat_buf: *mut Stat), | ||||
| @ -170,9 +171,9 @@ macro_rules! process_syscall_table_with_callback { | ||||
|             (Chdir = 80) => do_chdir(path: *const i8), | ||||
|             (Fchdir = 81) => do_fchdir(fd: FileDesc), | ||||
|             (Rename = 82) => do_rename(oldpath: *const i8, newpath: *const i8), | ||||
|             (Mkdir = 83) => do_mkdir(path: *const i8, mode: usize), | ||||
|             (Mkdir = 83) => do_mkdir(path: *const i8, mode: u16), | ||||
|             (Rmdir = 84) => do_rmdir(path: *const i8), | ||||
|             (Creat = 85) => do_creat(path: *const i8, mode: u32), | ||||
|             (Creat = 85) => do_creat(path: *const i8, mode: u16), | ||||
|             (Link = 86) => do_link(oldpath: *const i8, newpath: *const i8), | ||||
|             (Unlink = 87) => do_unlink(path: *const i8), | ||||
|             (Symlink = 88) => do_symlink(target: *const i8, link_path: *const i8), | ||||
| @ -182,7 +183,7 @@ macro_rules! process_syscall_table_with_callback { | ||||
|             (Chown = 92) => do_chown(path: *const i8, uid: u32, gid: u32), | ||||
|             (Fchown = 93) => do_fchown(fd: FileDesc, uid: u32, gid: u32), | ||||
|             (Lchown = 94) => do_lchown(path: *const i8, uid: u32, gid: u32), | ||||
|             (Umask = 95) => handle_unsupported(), | ||||
|             (Umask = 95) => do_umask(mask: u16), | ||||
|             (Gettimeofday = 96) => do_gettimeofday(tv_u: *mut timeval_t), | ||||
|             (Getrlimit = 97) => handle_unsupported(), | ||||
|             (Getrusage = 98) => handle_unsupported(), | ||||
| @ -344,8 +345,8 @@ macro_rules! process_syscall_table_with_callback { | ||||
|             (InotifyAddWatch = 254) => handle_unsupported(), | ||||
|             (InotifyRmWatch = 255) => handle_unsupported(), | ||||
|             (MigratePages = 256) => handle_unsupported(), | ||||
|             (Openat = 257) => do_openat(dirfd: i32, path: *const i8, flags: u32, mode: u32), | ||||
|             (Mkdirat = 258) => do_mkdirat(dirfd: i32, path: *const i8, mode: usize), | ||||
|             (Openat = 257) => do_openat(dirfd: i32, path: *const i8, flags: u32, mode: u16), | ||||
|             (Mkdirat = 258) => do_mkdirat(dirfd: i32, path: *const i8, mode: u16), | ||||
|             (Mknodat = 259) => handle_unsupported(), | ||||
|             (Fchownat = 260) => do_fchownat(dirfd: i32, path: *const i8, uid: u32, gid: u32, flags: i32), | ||||
|             (Futimesat = 261) => handle_unsupported(), | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| use super::*; | ||||
| use crate::fs::{AccessMode, CreationFlags, FsView}; | ||||
| use crate::fs::{AccessMode, CreationFlags, FileMode, FsView}; | ||||
| use resolv_conf::*; | ||||
| use std::ffi::CStr; | ||||
| use std::str; | ||||
| @ -11,7 +11,7 @@ pub fn write_resolv_conf() -> Result<()> { | ||||
|     let resolv_conf_file = fs_view.open_file( | ||||
|         RESOLV_CONF_PATH, | ||||
|         AccessMode::O_RDWR as u32 | CreationFlags::O_CREAT.bits() | CreationFlags::O_TRUNC.bits(), | ||||
|         0o666, | ||||
|         FileMode::from_bits(0o666).unwrap(), | ||||
|     )?; | ||||
|     let resolv_conf_str = RESOLV_CONF_STR.read().unwrap(); | ||||
|     match &*resolv_conf_str { | ||||
|  | ||||
| @ -19,7 +19,7 @@ TESTS ?= env empty hello_world malloc mmap file fs_perms getpid spawn sched pipe | ||||
| 	truncate readdir mkdir open stat link symlink chmod chown tls pthread system_info resolv_conf rlimit \
 | ||||
| 	server server_epoll unix_socket cout hostfs cpuid rdtsc device sleep exit_group \
 | ||||
| 	ioctl fcntl eventfd emulate_syscall access signal sysinfo prctl rename procfs wait \
 | ||||
| 	spawn_attribute exec statfs | ||||
| 	spawn_attribute exec statfs umask | ||||
| # Benchmarks: need to be compiled and run by bench-% target
 | ||||
| BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										5
									
								
								test/umask/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										5
									
								
								test/umask/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| include ../test_common.mk | ||||
| 
 | ||||
| EXTRA_C_FLAGS := | ||||
| EXTRA_LINK_FLAGS := | ||||
| BIN_ARGS := | ||||
							
								
								
									
										100
									
								
								test/umask/main.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										100
									
								
								test/umask/main.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,100 @@ | ||||
| #include <sys/stat.h> | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include "test_fs.h" | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // Helper function
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| static int remove_file(const char *file_path) { | ||||
|     int ret; | ||||
|     ret = unlink(file_path); | ||||
|     if (ret < 0) { | ||||
|         THROW_ERROR("failed to unlink the created file"); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int check_create_file_with_umask(const char *file_path, mode_t mask) { | ||||
|     mode_t mode = 00666; | ||||
|     int fd = creat(file_path, mode); | ||||
|     if (fd < 0) { | ||||
|         THROW_ERROR("failed to create file"); | ||||
|     } | ||||
| 
 | ||||
|     struct stat stat_buf; | ||||
|     if (fstat(fd, &stat_buf) < 0) { | ||||
|         THROW_ERROR("failed to stat file"); | ||||
|     } | ||||
|     mode_t actual_mode = stat_buf.st_mode & 00777; | ||||
|     if (actual_mode != (mode & ~mask)) { | ||||
|         THROW_ERROR("failed to check the mode with umask(%o), actual_mode is: %o", mask, | ||||
|                     actual_mode); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // Test cases for umask
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #define DEFAULT_UMASK (00022) | ||||
| 
 | ||||
| static int __test_create_file_with_default_umask(const char *file_path) { | ||||
|     if (check_create_file_with_umask(file_path, DEFAULT_UMASK) < 0) { | ||||
|         THROW_ERROR("failed to check default umask"); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int __test_umask(const char *file_path) { | ||||
|     mode_t new_mask = 00066; | ||||
|     int old_mask = umask(new_mask); | ||||
|     if (old_mask != DEFAULT_UMASK) { | ||||
|         THROW_ERROR("failed to get correct default mask"); | ||||
|     } | ||||
| 
 | ||||
|     if (check_create_file_with_umask(file_path, new_mask) < 0) { | ||||
|         THROW_ERROR("failed to check default umask"); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| typedef int(*test_file_func_t)(const char *); | ||||
| 
 | ||||
| static int test_file_framework(test_file_func_t fn) { | ||||
|     const char *file_path = "/root/test_filesystem_umask.txt"; | ||||
| 
 | ||||
|     if (fn(file_path) < 0) { | ||||
|         return -1; | ||||
|     } | ||||
|     if (remove_file(file_path) < 0) { | ||||
|         return -1; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int test_create_file_with_default_umask() { | ||||
|     return test_file_framework(__test_create_file_with_default_umask); | ||||
| } | ||||
| 
 | ||||
| static int test_umask() { | ||||
|     return test_file_framework(__test_umask); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // Test suite main
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| static test_case_t test_cases[] = { | ||||
|     TEST_CASE(test_create_file_with_default_umask), | ||||
|     TEST_CASE(test_umask), | ||||
| }; | ||||
| 
 | ||||
| int main(int argc, const char *argv[]) { | ||||
|     return test_suite_run(test_cases, ARRAY_SIZE(test_cases)); | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user