@@ -737,6 +737,112 @@ impl Syscall {
737
737
return do_mkdir ( & path, FileMode :: from_bits_truncate ( mode as u32 ) ) . map ( |x| x as usize ) ;
738
738
}
739
739
740
+ /// **创建硬连接的系统调用**
741
+ ///
742
+ /// ## 参数
743
+ ///
744
+ /// - 'oldfd': 用于解析源文件路径的文件描述符
745
+ /// - 'old': 源文件路径
746
+ /// - 'newfd': 用于解析新文件路径的文件描述符
747
+ /// - 'new': 新文件将创建的路径
748
+ /// - 'flags': 标志位,仅以位或方式包含AT_EMPTY_PATH和AT_SYMLINK_FOLLOW
749
+ ///
750
+ ///
751
+ pub fn do_linkat (
752
+ oldfd : i32 ,
753
+ old : & str ,
754
+ newfd : i32 ,
755
+ new : & str ,
756
+ flags : AtFlags ,
757
+ ) -> Result < usize , SystemError > {
758
+ // flag包含其他未规定值时返回EINVAL
759
+ if !( AtFlags :: AT_EMPTY_PATH | AtFlags :: AT_SYMLINK_FOLLOW ) . contains ( flags) {
760
+ return Err ( SystemError :: EINVAL ) ;
761
+ }
762
+ // TODO AT_EMPTY_PATH标志启用时,进行调用者CAP_DAC_READ_SEARCH或相似的检查
763
+ let symlink_times = if flags. contains ( AtFlags :: AT_SYMLINK_FOLLOW ) {
764
+ 0 as usize
765
+ } else {
766
+ VFS_MAX_FOLLOW_SYMLINK_TIMES
767
+ } ;
768
+ let pcb = ProcessManager :: current_pcb ( ) ;
769
+
770
+ // 得到源路径的inode
771
+ let old_inode: Arc < dyn IndexNode > = if old. is_empty ( ) {
772
+ if flags. contains ( AtFlags :: AT_EMPTY_PATH ) {
773
+ // 在AT_EMPTY_PATH启用时,old可以为空,old_inode实际为oldfd所指文件,但该文件不能为目录。
774
+ let binding = pcb. fd_table ( ) ;
775
+ let fd_table_guard = binding. read ( ) ;
776
+ let file = fd_table_guard
777
+ . get_file_by_fd ( oldfd)
778
+ . ok_or ( SystemError :: EBADF ) ?;
779
+ let old_inode = file. lock ( ) . inode ( ) ;
780
+ old_inode
781
+ } else {
782
+ return Err ( SystemError :: ENONET ) ;
783
+ }
784
+ } else {
785
+ let ( old_begin_inode, old_remain_path) = user_path_at ( & pcb, oldfd, old) ?;
786
+ old_begin_inode. lookup_follow_symlink ( & old_remain_path, symlink_times) ?
787
+ } ;
788
+
789
+ // old_inode为目录时返回EPERM
790
+ if old_inode. metadata ( ) . unwrap ( ) . file_type == FileType :: Dir {
791
+ return Err ( SystemError :: EPERM ) ;
792
+ }
793
+
794
+ // 得到新创建节点的父节点
795
+ let ( new_begin_inode, new_remain_path) = user_path_at ( & pcb, newfd, new) ?;
796
+ let ( new_name, new_parent_path) = rsplit_path ( & new_remain_path) ;
797
+ let new_parent = new_begin_inode
798
+ . lookup_follow_symlink ( & new_parent_path. unwrap_or ( "/" ) , symlink_times) ?;
799
+
800
+ // 被调用者利用downcast_ref判断两inode是否为同一文件系统
801
+ return new_parent. link ( & new_name, & old_inode) . map ( |_| 0 ) ;
802
+ }
803
+
804
+ pub fn link ( old : * const u8 , new : * const u8 ) -> Result < usize , SystemError > {
805
+ let get_path = |cstr : * const u8 | -> Result < String , SystemError > {
806
+ let res = check_and_clone_cstr ( cstr, Some ( MAX_PATHLEN ) ) ?;
807
+ if res. len ( ) >= MAX_PATHLEN {
808
+ return Err ( SystemError :: ENAMETOOLONG ) ;
809
+ }
810
+ if res. is_empty ( ) {
811
+ return Err ( SystemError :: ENOENT ) ;
812
+ }
813
+ Ok ( res)
814
+ } ;
815
+ let old = get_path ( old) ?;
816
+ let new = get_path ( new) ?;
817
+ return Self :: do_linkat (
818
+ AtFlags :: AT_FDCWD . bits ( ) as i32 ,
819
+ & old,
820
+ AtFlags :: AT_FDCWD . bits ( ) as i32 ,
821
+ & new,
822
+ AtFlags :: empty ( ) ,
823
+ ) ;
824
+ }
825
+
826
+ pub fn linkat (
827
+ oldfd : i32 ,
828
+ old : * const u8 ,
829
+ newfd : i32 ,
830
+ new : * const u8 ,
831
+ flags : i32 ,
832
+ ) -> Result < usize , SystemError > {
833
+ let old = check_and_clone_cstr ( old, Some ( MAX_PATHLEN ) ) ?;
834
+ let new = check_and_clone_cstr ( new, Some ( MAX_PATHLEN ) ) ?;
835
+ if old. len ( ) >= MAX_PATHLEN || new. len ( ) >= MAX_PATHLEN {
836
+ return Err ( SystemError :: ENAMETOOLONG ) ;
837
+ }
838
+ // old 根据flags & AtFlags::AT_EMPTY_PATH判空
839
+ if new. is_empty ( ) {
840
+ return Err ( SystemError :: ENOENT ) ;
841
+ }
842
+ let flags = AtFlags :: from_bits ( flags) . ok_or ( SystemError :: EINVAL ) ?;
843
+ Self :: do_linkat ( oldfd, & old, newfd, & new, flags)
844
+ }
845
+
740
846
/// **删除文件夹、取消文件的链接、删除文件的系统调用**
741
847
///
742
848
/// ## 参数
0 commit comments