1 /* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 use hilog_rust::{error, hilog, HiLogLabel, LogType}; 17 use libc::{__errno_location, c_char, c_uint, c_void}; 18 use std::ffi::{CStr, CString}; 19 use std::fs::File; 20 use std::io::{BufRead, BufReader, Error, ErrorKind, Seek, SeekFrom}; 21 #[cfg(unix)] 22 use std::os::unix::io::{FromRawFd, RawFd}; 23 use std::path::PathBuf; 24 use std::ptr::null_mut; 25 use std::{fs, mem}; 26 27 const LOG_LABEL: HiLogLabel = HiLogLabel { 28 log_type: LogType::LogCore, 29 domain: 0xD004388, 30 tag: "file_api", 31 }; 32 33 /// Enumeration of `lseek` interface to seek within a file. 34 #[repr(C)] 35 #[allow(dead_code)] 36 pub enum SeekPos { 37 Start, 38 Current, 39 End, 40 } 41 42 /// Enumeration of `mkdirs` interface to choose ways to create the direction. 43 #[repr(C)] 44 #[allow(dead_code)] 45 pub enum MakeDirectionMode { 46 Single, 47 Multiple, 48 } 49 50 /// Structure for storing string and its effective length. 51 #[repr(C)] 52 pub struct Str { 53 /// C string. 54 pub str: *mut c_char, 55 /// The length of string. 56 pub len: c_uint, 57 } 58 59 pub(crate) unsafe fn error_control(err: Error) { 60 let errno_pos = __errno_location(); 61 if let Some(raw) = err.raw_os_error() { 62 *errno_pos = raw; 63 } else { 64 match err.kind() { 65 ErrorKind::NotFound => *errno_pos = 2, 66 ErrorKind::PermissionDenied => *errno_pos = 13, 67 ErrorKind::AlreadyExists => *errno_pos = 17, 68 ErrorKind::InvalidInput => *errno_pos = 22, 69 ErrorKind::InvalidData => *errno_pos = 61, 70 _ => { 71 *errno_pos = 13900042; 72 error!(LOG_LABEL, "Unknown error is : {}", @public(err)); 73 } 74 } 75 } 76 } 77 78 pub(crate) unsafe fn reader_iterator(path: *const c_char) -> Result<*mut c_void, Error> { 79 if path.is_null() { 80 return Err(Error::new(ErrorKind::InvalidInput, "Invalid input")); 81 } 82 let path = CStr::from_ptr(path); 83 let path = match path.to_str() { 84 Ok(p) => p, 85 Err(_) => { 86 return Err(Error::new(ErrorKind::InvalidInput, "Invalid input")); 87 } 88 }; 89 let file = File::open(path)?; 90 let reader = BufReader::new(file); 91 Ok(Box::into_raw(Box::new(reader)) as *mut c_void) 92 } 93 94 pub(crate) unsafe fn drop_reader_iterator(iter: *mut c_void) { 95 if iter.is_null() { 96 return; 97 } 98 let reader = Box::from_raw(iter as *mut BufReader<File>); 99 drop(reader); 100 } 101 102 pub(crate) unsafe fn next_line(iter: *mut c_void) -> Result<*mut Str, Error> { 103 if iter.is_null() { 104 return Err(Error::new(ErrorKind::InvalidInput, "Invalid input")); 105 } 106 let reader = &mut *(iter as *mut BufReader<File>); 107 let mut line = String::new(); 108 let len = reader.read_line(&mut line)? as c_uint; 109 if len > 0 { 110 let line_bytes = line.into_bytes(); 111 let line = CString::from_vec_unchecked(line_bytes); 112 let item = Str { 113 str: line.into_raw(), 114 len, 115 }; 116 Ok(Box::into_raw(Box::new(item))) 117 } else { 118 Ok(null_mut()) 119 } 120 } 121 122 pub(crate) fn seek(fd: i32, offset: i64, pos: SeekPos) -> Result<u64, Error> { 123 let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; 124 125 let new_pos = match pos { 126 SeekPos::Start => file.seek(SeekFrom::Start(offset as u64)), 127 SeekPos::Current => file.seek(SeekFrom::Current(offset)), 128 SeekPos::End => file.seek(SeekFrom::End(offset)), 129 }; 130 131 mem::forget(file); 132 new_pos 133 } 134 135 pub(crate) fn create_dir(path: *const c_char, mode: MakeDirectionMode) -> Result<(), Error> { 136 if path.is_null() { 137 return Err(Error::new(ErrorKind::InvalidInput, "Invalid input")); 138 } 139 let path = unsafe { CStr::from_ptr(path) }; 140 let path = match path.to_str() { 141 Ok(p) => p, 142 Err(_) => { 143 return Err(Error::new(ErrorKind::InvalidInput, "Invalid input")); 144 } 145 }; 146 match mode { 147 MakeDirectionMode::Single => fs::create_dir(path), 148 MakeDirectionMode::Multiple => fs::create_dir_all(path), 149 } 150 } 151 152 pub(crate) fn get_parent(fd: i32) -> Result<*mut Str, Error> { 153 let mut p = PathBuf::from("/proc/self/fd"); 154 p.push(&fd.to_string()); 155 let path = fs::read_link(&p)?; 156 match path.as_path().parent() { 157 None => {} 158 Some(parent) => { 159 if let Some(str) = parent.to_str() { 160 // When the return value of `Path::parent()` is `Some(s)`, `s` will not be empty 161 // string. 162 let par_path = CString::new(str).unwrap(); 163 let len = par_path.as_bytes().len() as c_uint; 164 let item = Str { 165 str: par_path.into_raw(), 166 len, 167 }; 168 return Ok(Box::into_raw(Box::new(item))); 169 } 170 } 171 } 172 Ok(null_mut()) 173 } 174 175 pub(crate) unsafe fn cut_file_name(path: *const c_char, size: usize) -> *mut Str { 176 let path_str = match CStr::from_ptr(path).to_str() { 177 Ok(s) => s, 178 Err(_) => return std::ptr::null_mut(), 179 }; 180 let len = path_str.chars().count(); 181 let size = size.min(len); 182 183 let mut sliced_str = String::from(path_str); 184 for _ in 0..size { 185 let _ = sliced_str.pop(); 186 } 187 188 let result = match CString::new(sliced_str.clone()) { 189 Ok(s) => Str { 190 str: s.into_raw(), 191 len: sliced_str.as_bytes().len() as c_uint, 192 }, 193 Err(_) => return std::ptr::null_mut(), 194 }; 195 Box::into_raw(Box::new(result)) 196 } 197