• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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