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 libc::{__errno_location, c_char, c_uint};
17 use std::ffi::{CStr, CString};
18 use std::fs::File;
19 use std::io::{BufRead, BufReader, Error, ErrorKind, Seek, SeekFrom};
20 #[cfg(unix)]
21 use std::os::unix::io::{FromRawFd, RawFd};
22 use std::path::PathBuf;
23 use std::ptr::null_mut;
24 use std::{fs, mem};
25
26 /// Enumeration of `lseek` interface to seek within a file.
27 #[repr(C)]
28 #[allow(dead_code)]
29 pub enum SeekPos {
30 Start,
31 Current,
32 End,
33 }
34
35 /// Enumeration of `mkdirs` interface to choose ways to create the direction.
36 #[repr(C)]
37 #[allow(dead_code)]
38 pub enum MakeDirectionMode {
39 Single,
40 Multiple,
41 }
42
43 /// Structure for storing string and its effective length.
44 #[repr(C)]
45 pub struct Str {
46 /// C string.
47 pub str: *const c_char,
48 /// The length of string.
49 pub len: c_uint,
50 }
51
52 /// Structure for storing file information by line.
53 #[derive(Debug, Default)]
54 pub struct StringVector {
55 pub(crate) vec: Vec<String>,
56 pub(crate) len: usize,
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 _ => unreachable!("Unexpected error type"),
70 }
71 }
72 }
73
read_lines(path: *const c_char) -> Result<*mut StringVector, Error>74 pub(crate) unsafe fn read_lines(path: *const c_char) -> Result<*mut StringVector, Error> {
75 if path.is_null() {
76 return Err(Error::new(ErrorKind::InvalidInput, "Invalid input"));
77 }
78 let path = CStr::from_ptr(path);
79 let path = match path.to_str() {
80 Ok(p) => p,
81 Err(_) => {
82 return Err(Error::new(ErrorKind::InvalidInput, "Invalid input"));
83 }
84 };
85 let mut lines = StringVector::default();
86 let file = File::open(path)?;
87 let mut reader = BufReader::new(file);
88 loop {
89 let mut line = String::new();
90 let len = reader.read_line(&mut line)?;
91 if len > 0 {
92 lines.vec.push(line);
93 } else {
94 return Ok(Box::into_raw(Box::new(lines)));
95 }
96 }
97 }
98
next_line(lines: *mut StringVector) -> Result<*mut Str, Error>99 pub(crate) unsafe fn next_line(lines: *mut StringVector) -> Result<*mut Str, Error> {
100 if lines.is_null() {
101 return Err(Error::new(ErrorKind::InvalidInput, "Invalid input"));
102 }
103 let lines = &mut *lines;
104 let cnt = lines.len;
105 if cnt < lines.vec.len() {
106 let line = lines.vec[cnt].as_ptr() as *const c_char;
107 let len = lines.vec[cnt].len() as c_uint;
108 let item = Str { str: line, len };
109 lines.len += 1;
110 Ok(Box::into_raw(Box::new(item)))
111 } else {
112 Ok(null_mut())
113 }
114 }
115
seek(fd: i32, offset: i64, pos: SeekPos) -> Result<(), Error>116 pub(crate) fn seek(fd: i32, offset: i64, pos: SeekPos) -> Result<(), Error> {
117 let mut file = unsafe { File::from_raw_fd(fd as RawFd) };
118
119 match pos {
120 SeekPos::Start => file.seek(SeekFrom::Start(offset as u64))?,
121 SeekPos::Current => file.seek(SeekFrom::Current(offset))?,
122 SeekPos::End => file.seek(SeekFrom::End(offset))?,
123 };
124
125 mem::forget(file);
126 Ok(())
127 }
128
create_dir(path: *const c_char, mode: MakeDirectionMode) -> Result<(), Error>129 pub(crate) fn create_dir(path: *const c_char, mode: MakeDirectionMode) -> Result<(), Error> {
130 if path.is_null() {
131 return Err(Error::new(ErrorKind::InvalidInput, "Invalid input"));
132 }
133 let path = unsafe { CStr::from_ptr(path) };
134 let path = match path.to_str() {
135 Ok(p) => p,
136 Err(_) => {
137 return Err(Error::new(ErrorKind::InvalidInput, "Invalid input"));
138 }
139 };
140 match mode {
141 MakeDirectionMode::Single => fs::create_dir(path),
142 MakeDirectionMode::Multiple => fs::create_dir_all(path),
143 }
144 }
145
get_parent(fd: i32) -> Result<*mut Str, Error>146 pub(crate) fn get_parent(fd: i32) -> Result<*mut Str, Error> {
147 let mut p = PathBuf::from("/proc/self/fd");
148 p.push(&fd.to_string());
149 let path = fs::read_link(&p)?;
150 match path.as_path().parent() {
151 None => {}
152 Some(parent) => {
153 if let Some(str) = parent.to_str() {
154 // When the return value of `Path::parent()` is `Some(s)`, `s` will not be empty
155 // string.
156 let par_path = CString::new(str).unwrap();
157 let len = par_path.as_bytes().len() as c_uint;
158 let item = Str {
159 str: par_path.into_raw() as *const c_char,
160 len,
161 };
162 return Ok(Box::into_raw(Box::new(item)));
163 }
164 }
165 }
166 Ok(null_mut())
167 }
168