@@ -735,41 +735,39 @@ impl<'a> filesystem::types::HostDescriptor for VfsCtxView<'a> {
735735 let base_node = Arc :: clone ( & base_desc. node ) ;
736736 let base_flags = base_desc. flags ;
737737
738- let wants_create = open_flags. contains ( OpenFlags :: CREATE ) ;
739- let wants_exclusive = open_flags. contains ( OpenFlags :: EXCLUSIVE ) ;
740- let wants_directory = open_flags. contains ( OpenFlags :: DIRECTORY ) ;
741- let wants_truncate = open_flags. contains ( OpenFlags :: TRUNCATE ) ;
738+ let create = open_flags. contains ( OpenFlags :: CREATE ) ;
739+ let directory = open_flags. contains ( OpenFlags :: DIRECTORY ) ;
740+ let exclusive = open_flags. contains ( OpenFlags :: EXCLUSIVE ) ;
741+ let truncate = open_flags. contains ( OpenFlags :: TRUNCATE ) ;
742742
743743 // Per POSIX: O_CREAT only creates regular files, not directories.
744744 // https://github.com/WebAssembly/WASI/blob/184b0c0e9fd437e5e5601d6e327a28feddbbd7f7/proposals/filesystem/wit/types.wit#L145-L146
745745 // "If O_CREAT and O_DIRECTORY are set and the requested access mode is neither
746746 // O_WRONLY nor O_RDWR, the result is unspecified."
747747 // We choose to disallow this combination entirely.
748- if wants_create && wants_directory {
748+ if create && directory {
749749 return Err ( FsError :: trap ( ErrorCode :: Invalid ) ) ;
750750 }
751751
752752 // Try to resolve the path to an existing node
753753 let existing = self . get_node_from_start ( & path, Arc :: clone ( & base_node) ) ;
754754
755- // Per POSIX O_DIRECTORY: "If path resolves to a non-directory file, fail and set errno to [ENOTDIR]."
756- let node = match existing {
757- Ok ( node) if wants_directory => {
755+ let node = match ( existing, create, directory, exclusive, truncate) {
756+ ( Ok ( node) , true , _, false , _) => node, // Per POSIX: "If the file exists, O_CREAT has no effect except as noted under O_EXCL below.
757+ ( Ok ( _) , true , _, true , _) => {
758+ // Per POSIX: "O_CREAT and O_EXCL are set, open() shall fail if the file exists"
759+ return Err ( FsError :: trap ( ErrorCode :: Exist ) ) ;
760+ }
761+ ( Ok ( node) , false , true , false , false ) => {
762+ // Per POSIX: "O_DIRECTORY: "If path resolves to a non-directory file, fail and set errno to [ENOTDIR]."
758763 let guard = node. read ( ) . unwrap ( ) ;
759764 if !matches ! ( guard. kind, VfsNodeKind :: Directory { .. } ) {
760765 return Err ( FsError :: trap ( ErrorCode :: NotDirectory ) ) ;
761766 }
762767 drop ( guard) ;
763768 node
764769 }
765- Ok ( node) if wants_exclusive => {
766- if wants_create {
767- // Per POSIX: "O_CREAT and O_EXCL are set, open() shall fail if the file exists"
768- return Err ( FsError :: trap ( ErrorCode :: Exist ) ) ;
769- }
770- node
771- }
772- Ok ( node) if wants_truncate => {
770+ ( Ok ( node) , _, _, _, true ) => {
773771 let mut guard = node. write ( ) . unwrap ( ) ;
774772 match & mut guard. kind {
775773 VfsNodeKind :: File { content } => {
@@ -791,14 +789,15 @@ impl<'a> filesystem::types::HostDescriptor for VfsCtxView<'a> {
791789 drop ( guard) ;
792790 node
793791 }
794- Ok ( node) => node,
795- Err ( _) => {
796- if !wants_create {
797- // Per POSIX [ENOENT]: "O_CREAT is not set and a component of path does
798- // not name an existing file"
799- return Err ( FsError :: trap ( ErrorCode :: NoEntry ) ) ;
800- }
801-
792+ ( Ok ( node) , _, _, _, _) => node,
793+ ( Err ( _) , false , _, _, _) => {
794+ // "If O_CREAT is not set and the file does not exist, open()
795+ // shall fail and set errno to [ENOENT]."
796+ return Err ( FsError :: trap ( ErrorCode :: NoEntry ) ) ;
797+ }
798+ ( Err ( _) , true , _, _, _) => {
799+ // "If O_CREAT is set and the file does not exist, it shall be
800+ // created as a regular file with permissions"
802801 if !base_flags. contains ( DescriptorFlags :: MUTATE_DIRECTORY ) {
803802 return Err ( FsError :: trap ( ErrorCode :: ReadOnly ) ) ;
804803 }
@@ -1780,7 +1779,7 @@ mod tests {
17801779 desc,
17811780 PathFlags :: empty( ) ,
17821781 "existingfile" . to_string( ) ,
1783- OpenFlags :: CREATE | OpenFlags :: TRUNCATE ,
1782+ OpenFlags :: TRUNCATE ,
17841783 DescriptorFlags :: READ | DescriptorFlags :: WRITE ,
17851784 )
17861785 . await ;
0 commit comments