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