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 
error_control(err: Error)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 
reader_iterator(path: *const c_char) -> Result<*mut c_void, Error>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 
drop_reader_iterator(iter: *mut c_void)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 
next_line(iter: *mut c_void) -> Result<*mut Str, Error>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 
seek(fd: i32, offset: i64, pos: SeekPos) -> Result<u64, Error>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 
create_dir(path: *const c_char, mode: MakeDirectionMode) -> Result<(), Error>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 
get_parent(fd: i32) -> Result<*mut Str, Error>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 
cut_file_name(path: *const c_char, size: usize) -> *mut Str175 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