@@ -838,7 +838,7 @@ impl From<RmdirError> for isize {
838
838
}
839
839
840
840
/// Truncate a file to the given length.
841
- ///
841
+ ///
842
842
/// # Errors
843
843
/// See [`TruncateError`] for more details.
844
844
pub fn truncate ( path : usize , len : usize ) -> Result < usize , TruncateError > {
@@ -922,9 +922,7 @@ impl From<user::string::FetchError> for TruncateError {
922
922
923
923
impl From < vfs:: inode:: TruncateError > for TruncateError {
924
924
fn from ( error : vfs:: inode:: TruncateError ) -> Self {
925
- match error {
926
-
927
- }
925
+ match error { }
928
926
}
929
927
}
930
928
@@ -950,7 +948,7 @@ pub struct Stat {
950
948
951
949
/// Number of hard links
952
950
pub nlink : u64 ,
953
-
951
+
954
952
/// Unix timestamp of the last access
955
953
pub atime : Timespec ,
956
954
@@ -961,6 +959,10 @@ pub struct Stat {
961
959
pub ctime : Timespec ,
962
960
}
963
961
962
+ /// Get information about a file.
963
+ ///
964
+ /// # Errors
965
+ /// See [`StatError`] for more details.
964
966
pub fn stat ( path : usize , stat : usize ) -> Result < usize , StatError > {
965
967
let ptr = user:: Pointer :: < SyscallString > :: from_usize ( path) . ok_or ( StatError :: BadAddress ) ?;
966
968
let path = user:: String :: from_raw_ptr ( & ptr)
@@ -978,14 +980,23 @@ pub fn stat(path: usize, stat: usize) -> Result<usize, StatError> {
978
980
let inode = dentry. inode ( ) ;
979
981
let state = inode. state . lock ( ) ;
980
982
let stat = Stat {
981
- dev : 0 , // TODO
982
- kind : 0 , // TODO
983
+ dev : 0 , // TODO
984
+ kind : 0 , // TODO
983
985
ino : inode. id . 0 ,
984
986
size : state. size as u64 ,
985
987
nlink : state. links ,
986
- atime : Timespec { seconds : state. access_time . 0 . 0 , nanoseconds : 0 } ,
987
- ctime : Timespec { seconds : state. access_time . 0 . 0 , nanoseconds : 0 } ,
988
- mtime : Timespec { seconds : state. access_time . 0 . 0 , nanoseconds : 0 } ,
988
+ atime : Timespec {
989
+ seconds : state. access_time . 0 . 0 ,
990
+ nanoseconds : 0 ,
991
+ } ,
992
+ ctime : Timespec {
993
+ seconds : state. access_time . 0 . 0 ,
994
+ nanoseconds : 0 ,
995
+ } ,
996
+ mtime : Timespec {
997
+ seconds : state. access_time . 0 . 0 ,
998
+ nanoseconds : 0 ,
999
+ } ,
989
1000
} ;
990
1001
991
1002
unsafe {
@@ -1053,3 +1064,109 @@ impl From<StatError> for isize {
1053
1064
-( error as isize )
1054
1065
}
1055
1066
}
1067
+
1068
+ #[ repr( C ) ]
1069
+ pub struct Dirent {
1070
+ pub ino : u64 ,
1071
+ pub kind : u16 ,
1072
+ pub name_len : u16 ,
1073
+ pub name : [ u8 ; vfs:: name:: Name :: MAX_LEN ] ,
1074
+ }
1075
+
1076
+ impl Dirent {
1077
+ pub const UNKNOWN : u16 = 0 ;
1078
+ pub const REGULAR : u16 = 1 ;
1079
+ pub const DIRECTORY : u16 = 2 ;
1080
+ pub const CHAR_DEVICE : u16 = 3 ;
1081
+ pub const BLOCK_DEVICE : u16 = 4 ;
1082
+
1083
+ #[ must_use]
1084
+ pub const fn convert_inode_type ( kind : vfs:: dirent:: Kind ) -> u16 {
1085
+ match kind {
1086
+ vfs:: dirent:: Kind :: File => Self :: REGULAR ,
1087
+ vfs:: dirent:: Kind :: Directory => Self :: DIRECTORY ,
1088
+ vfs:: dirent:: Kind :: CharDevice => Self :: CHAR_DEVICE ,
1089
+ vfs:: dirent:: Kind :: BlockDevice => Self :: BLOCK_DEVICE ,
1090
+ }
1091
+ }
1092
+ }
1093
+
1094
+
1095
+ /// Read a directory entry from the directory descriptor `fd` into the
1096
+ /// buffer `dirent` from the current position of the directory.
1097
+ ///
1098
+ /// # Errors
1099
+ /// See [`ReaddirError`] for more details.
1100
+ pub fn readdir ( fd : usize , dirent : usize ) -> Result < usize , ReaddirError > {
1101
+ let current_task = SCHEDULER . current_task ( ) ;
1102
+ let file = current_task
1103
+ . files ( )
1104
+ . lock ( )
1105
+ . get ( vfs:: fd:: Descriptor ( fd) )
1106
+ . ok_or ( ReaddirError :: InvalidFileDescriptor ) ?
1107
+ . clone ( ) ;
1108
+
1109
+ let ptr = user:: Pointer :: < Dirent > :: from_usize ( dirent) . ok_or ( ReaddirError :: BadAddress ) ?;
1110
+
1111
+ // Check that the file was opened for reading
1112
+ if !file. open_flags . contains ( vfs:: file:: OpenFlags :: READ ) {
1113
+ return Err ( ReaddirError :: NotReadable ) ;
1114
+ }
1115
+
1116
+ let dirent = file
1117
+ . as_directory ( )
1118
+ . ok_or ( ReaddirError :: NotADirectory ) ?
1119
+ . readdir ( & file, file. state . lock ( ) . offset ) ?;
1120
+
1121
+ file. state . lock ( ) . offset . 0 += 1 ;
1122
+
1123
+ unsafe {
1124
+ #[ allow( clippy:: cast_possible_truncation) ]
1125
+ user:: Object :: write ( & ptr, & Dirent {
1126
+ ino : dirent. inode . 0 ,
1127
+ kind : Dirent :: convert_inode_type ( dirent. kind ) ,
1128
+ name_len : dirent. name . len ( ) as u16 ,
1129
+ name : dirent. name . as_bytes ( ) . try_into ( ) . unwrap_or ( [ 0 ; 255 ] ) ,
1130
+ } ) ;
1131
+ }
1132
+ Ok ( 0 )
1133
+ }
1134
+
1135
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
1136
+ #[ repr( usize ) ]
1137
+ pub enum ReaddirError {
1138
+ /// The syscall number is invalid.
1139
+ NoSuchSyscall = 1 ,
1140
+
1141
+ /// The file descriptor is invalid
1142
+ InvalidFileDescriptor ,
1143
+
1144
+ /// The path passed as an argument
1145
+ BadAddress ,
1146
+
1147
+ /// The descriptor is not a directory
1148
+ NotADirectory ,
1149
+
1150
+ /// The directory is not readable
1151
+ NotReadable ,
1152
+
1153
+ /// The directory has no entries remaning
1154
+ EndOfDirectory ,
1155
+
1156
+ /// An unknown error occurred
1157
+ UnknownError ,
1158
+ }
1159
+
1160
+ impl From < vfs:: file:: ReaddirError > for ReaddirError {
1161
+ fn from ( error : vfs:: file:: ReaddirError ) -> Self {
1162
+ match error {
1163
+ vfs:: file:: ReaddirError :: EndOfDirectory => ReaddirError :: EndOfDirectory ,
1164
+ }
1165
+ }
1166
+ }
1167
+
1168
+ impl From < ReaddirError > for isize {
1169
+ fn from ( error : ReaddirError ) -> Self {
1170
+ -( error as isize )
1171
+ }
1172
+ }
0 commit comments