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