15bebb993Sopenharmony_ci/* 25bebb993Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 35bebb993Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 45bebb993Sopenharmony_ci * you may not use this file except in compliance with the License. 55bebb993Sopenharmony_ci * You may obtain a copy of the License at 65bebb993Sopenharmony_ci * 75bebb993Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 85bebb993Sopenharmony_ci * 95bebb993Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 105bebb993Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 115bebb993Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 125bebb993Sopenharmony_ci * See the License for the specific language governing permissions and 135bebb993Sopenharmony_ci * limitations under the License. 145bebb993Sopenharmony_ci */ 155bebb993Sopenharmony_ci 165bebb993Sopenharmony_ciuse hilog_rust::{error, hilog, HiLogLabel, LogType}; 175bebb993Sopenharmony_ciuse libc::{__errno_location, c_char, c_uint, c_void}; 185bebb993Sopenharmony_ciuse std::ffi::{CStr, CString}; 195bebb993Sopenharmony_ciuse std::fs::File; 205bebb993Sopenharmony_ciuse std::io::{BufRead, BufReader, Error, ErrorKind, Seek, SeekFrom}; 215bebb993Sopenharmony_ci#[cfg(unix)] 225bebb993Sopenharmony_ciuse std::os::unix::io::{FromRawFd, RawFd}; 235bebb993Sopenharmony_ciuse std::path::PathBuf; 245bebb993Sopenharmony_ciuse std::ptr::null_mut; 255bebb993Sopenharmony_ciuse std::{fs, mem}; 265bebb993Sopenharmony_ci 275bebb993Sopenharmony_ciconst LOG_LABEL: HiLogLabel = HiLogLabel { 285bebb993Sopenharmony_ci log_type: LogType::LogCore, 295bebb993Sopenharmony_ci domain: 0xD004388, 305bebb993Sopenharmony_ci tag: "file_api", 315bebb993Sopenharmony_ci}; 325bebb993Sopenharmony_ci 335bebb993Sopenharmony_ci/// Enumeration of `lseek` interface to seek within a file. 345bebb993Sopenharmony_ci#[repr(C)] 355bebb993Sopenharmony_ci#[allow(dead_code)] 365bebb993Sopenharmony_cipub enum SeekPos { 375bebb993Sopenharmony_ci Start, 385bebb993Sopenharmony_ci Current, 395bebb993Sopenharmony_ci End, 405bebb993Sopenharmony_ci} 415bebb993Sopenharmony_ci 425bebb993Sopenharmony_ci/// Enumeration of `mkdirs` interface to choose ways to create the direction. 435bebb993Sopenharmony_ci#[repr(C)] 445bebb993Sopenharmony_ci#[allow(dead_code)] 455bebb993Sopenharmony_cipub enum MakeDirectionMode { 465bebb993Sopenharmony_ci Single, 475bebb993Sopenharmony_ci Multiple, 485bebb993Sopenharmony_ci} 495bebb993Sopenharmony_ci 505bebb993Sopenharmony_ci/// Structure for storing string and its effective length. 515bebb993Sopenharmony_ci#[repr(C)] 525bebb993Sopenharmony_cipub struct Str { 535bebb993Sopenharmony_ci /// C string. 545bebb993Sopenharmony_ci pub str: *mut c_char, 555bebb993Sopenharmony_ci /// The length of string. 565bebb993Sopenharmony_ci pub len: c_uint, 575bebb993Sopenharmony_ci} 585bebb993Sopenharmony_ci 595bebb993Sopenharmony_cipub(crate) unsafe fn error_control(err: Error) { 605bebb993Sopenharmony_ci let errno_pos = __errno_location(); 615bebb993Sopenharmony_ci if let Some(raw) = err.raw_os_error() { 625bebb993Sopenharmony_ci *errno_pos = raw; 635bebb993Sopenharmony_ci } else { 645bebb993Sopenharmony_ci match err.kind() { 655bebb993Sopenharmony_ci ErrorKind::NotFound => *errno_pos = 2, 665bebb993Sopenharmony_ci ErrorKind::PermissionDenied => *errno_pos = 13, 675bebb993Sopenharmony_ci ErrorKind::AlreadyExists => *errno_pos = 17, 685bebb993Sopenharmony_ci ErrorKind::InvalidInput => *errno_pos = 22, 695bebb993Sopenharmony_ci ErrorKind::InvalidData => *errno_pos = 61, 705bebb993Sopenharmony_ci _ => { 715bebb993Sopenharmony_ci *errno_pos = 13900042; 725bebb993Sopenharmony_ci error!(LOG_LABEL, "Unknown error is : {}", @public(err)); 735bebb993Sopenharmony_ci } 745bebb993Sopenharmony_ci } 755bebb993Sopenharmony_ci } 765bebb993Sopenharmony_ci} 775bebb993Sopenharmony_ci 785bebb993Sopenharmony_cipub(crate) unsafe fn reader_iterator(path: *const c_char) -> Result<*mut c_void, Error> { 795bebb993Sopenharmony_ci if path.is_null() { 805bebb993Sopenharmony_ci return Err(Error::new(ErrorKind::InvalidInput, "Invalid input")); 815bebb993Sopenharmony_ci } 825bebb993Sopenharmony_ci let path = CStr::from_ptr(path); 835bebb993Sopenharmony_ci let path = match path.to_str() { 845bebb993Sopenharmony_ci Ok(p) => p, 855bebb993Sopenharmony_ci Err(_) => { 865bebb993Sopenharmony_ci return Err(Error::new(ErrorKind::InvalidInput, "Invalid input")); 875bebb993Sopenharmony_ci } 885bebb993Sopenharmony_ci }; 895bebb993Sopenharmony_ci let file = File::open(path)?; 905bebb993Sopenharmony_ci let reader = BufReader::new(file); 915bebb993Sopenharmony_ci Ok(Box::into_raw(Box::new(reader)) as *mut c_void) 925bebb993Sopenharmony_ci} 935bebb993Sopenharmony_ci 945bebb993Sopenharmony_cipub(crate) unsafe fn drop_reader_iterator(iter: *mut c_void) { 955bebb993Sopenharmony_ci if iter.is_null() { 965bebb993Sopenharmony_ci return; 975bebb993Sopenharmony_ci } 985bebb993Sopenharmony_ci let reader = Box::from_raw(iter as *mut BufReader<File>); 995bebb993Sopenharmony_ci drop(reader); 1005bebb993Sopenharmony_ci} 1015bebb993Sopenharmony_ci 1025bebb993Sopenharmony_cipub(crate) unsafe fn next_line(iter: *mut c_void) -> Result<*mut Str, Error> { 1035bebb993Sopenharmony_ci if iter.is_null() { 1045bebb993Sopenharmony_ci return Err(Error::new(ErrorKind::InvalidInput, "Invalid input")); 1055bebb993Sopenharmony_ci } 1065bebb993Sopenharmony_ci let reader = &mut *(iter as *mut BufReader<File>); 1075bebb993Sopenharmony_ci let mut line = String::new(); 1085bebb993Sopenharmony_ci let len = reader.read_line(&mut line)? as c_uint; 1095bebb993Sopenharmony_ci if len > 0 { 1105bebb993Sopenharmony_ci let line_bytes = line.into_bytes(); 1115bebb993Sopenharmony_ci let line = CString::from_vec_unchecked(line_bytes); 1125bebb993Sopenharmony_ci let item = Str { 1135bebb993Sopenharmony_ci str: line.into_raw(), 1145bebb993Sopenharmony_ci len, 1155bebb993Sopenharmony_ci }; 1165bebb993Sopenharmony_ci Ok(Box::into_raw(Box::new(item))) 1175bebb993Sopenharmony_ci } else { 1185bebb993Sopenharmony_ci Ok(null_mut()) 1195bebb993Sopenharmony_ci } 1205bebb993Sopenharmony_ci} 1215bebb993Sopenharmony_ci 1225bebb993Sopenharmony_cipub(crate) fn seek(fd: i32, offset: i64, pos: SeekPos) -> Result<u64, Error> { 1235bebb993Sopenharmony_ci let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; 1245bebb993Sopenharmony_ci 1255bebb993Sopenharmony_ci let new_pos = match pos { 1265bebb993Sopenharmony_ci SeekPos::Start => file.seek(SeekFrom::Start(offset as u64)), 1275bebb993Sopenharmony_ci SeekPos::Current => file.seek(SeekFrom::Current(offset)), 1285bebb993Sopenharmony_ci SeekPos::End => file.seek(SeekFrom::End(offset)), 1295bebb993Sopenharmony_ci }; 1305bebb993Sopenharmony_ci 1315bebb993Sopenharmony_ci mem::forget(file); 1325bebb993Sopenharmony_ci new_pos 1335bebb993Sopenharmony_ci} 1345bebb993Sopenharmony_ci 1355bebb993Sopenharmony_cipub(crate) fn create_dir(path: *const c_char, mode: MakeDirectionMode) -> Result<(), Error> { 1365bebb993Sopenharmony_ci if path.is_null() { 1375bebb993Sopenharmony_ci return Err(Error::new(ErrorKind::InvalidInput, "Invalid input")); 1385bebb993Sopenharmony_ci } 1395bebb993Sopenharmony_ci let path = unsafe { CStr::from_ptr(path) }; 1405bebb993Sopenharmony_ci let path = match path.to_str() { 1415bebb993Sopenharmony_ci Ok(p) => p, 1425bebb993Sopenharmony_ci Err(_) => { 1435bebb993Sopenharmony_ci return Err(Error::new(ErrorKind::InvalidInput, "Invalid input")); 1445bebb993Sopenharmony_ci } 1455bebb993Sopenharmony_ci }; 1465bebb993Sopenharmony_ci match mode { 1475bebb993Sopenharmony_ci MakeDirectionMode::Single => fs::create_dir(path), 1485bebb993Sopenharmony_ci MakeDirectionMode::Multiple => fs::create_dir_all(path), 1495bebb993Sopenharmony_ci } 1505bebb993Sopenharmony_ci} 1515bebb993Sopenharmony_ci 1525bebb993Sopenharmony_cipub(crate) fn get_parent(fd: i32) -> Result<*mut Str, Error> { 1535bebb993Sopenharmony_ci let mut p = PathBuf::from("/proc/self/fd"); 1545bebb993Sopenharmony_ci p.push(&fd.to_string()); 1555bebb993Sopenharmony_ci let path = fs::read_link(&p)?; 1565bebb993Sopenharmony_ci match path.as_path().parent() { 1575bebb993Sopenharmony_ci None => {} 1585bebb993Sopenharmony_ci Some(parent) => { 1595bebb993Sopenharmony_ci if let Some(str) = parent.to_str() { 1605bebb993Sopenharmony_ci // When the return value of `Path::parent()` is `Some(s)`, `s` will not be empty 1615bebb993Sopenharmony_ci // string. 1625bebb993Sopenharmony_ci let par_path = CString::new(str).unwrap(); 1635bebb993Sopenharmony_ci let len = par_path.as_bytes().len() as c_uint; 1645bebb993Sopenharmony_ci let item = Str { 1655bebb993Sopenharmony_ci str: par_path.into_raw(), 1665bebb993Sopenharmony_ci len, 1675bebb993Sopenharmony_ci }; 1685bebb993Sopenharmony_ci return Ok(Box::into_raw(Box::new(item))); 1695bebb993Sopenharmony_ci } 1705bebb993Sopenharmony_ci } 1715bebb993Sopenharmony_ci } 1725bebb993Sopenharmony_ci Ok(null_mut()) 1735bebb993Sopenharmony_ci} 1745bebb993Sopenharmony_ci 1755bebb993Sopenharmony_cipub(crate) unsafe fn cut_file_name(path: *const c_char, size: usize) -> *mut Str { 1765bebb993Sopenharmony_ci let path_str = match CStr::from_ptr(path).to_str() { 1775bebb993Sopenharmony_ci Ok(s) => s, 1785bebb993Sopenharmony_ci Err(_) => return std::ptr::null_mut(), 1795bebb993Sopenharmony_ci }; 1805bebb993Sopenharmony_ci let len = path_str.chars().count(); 1815bebb993Sopenharmony_ci let size = size.min(len); 1825bebb993Sopenharmony_ci 1835bebb993Sopenharmony_ci let mut sliced_str = String::from(path_str); 1845bebb993Sopenharmony_ci for _ in 0..size { 1855bebb993Sopenharmony_ci let _ = sliced_str.pop(); 1865bebb993Sopenharmony_ci } 1875bebb993Sopenharmony_ci 1885bebb993Sopenharmony_ci let result = match CString::new(sliced_str.clone()) { 1895bebb993Sopenharmony_ci Ok(s) => Str { 1905bebb993Sopenharmony_ci str: s.into_raw(), 1915bebb993Sopenharmony_ci len: sliced_str.as_bytes().len() as c_uint, 1925bebb993Sopenharmony_ci }, 1935bebb993Sopenharmony_ci Err(_) => return std::ptr::null_mut(), 1945bebb993Sopenharmony_ci }; 1955bebb993Sopenharmony_ci Box::into_raw(Box::new(result)) 1965bebb993Sopenharmony_ci} 197