1 // Copyright (C) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::cell::UnsafeCell;
15 use std::fs::{File, OpenOptions};
16 use std::io;
17 use std::os::fd::FromRawFd;
18 
19 use ylong_runtime::fs::File as AsyncFile;
20 
21 use crate::task::bundle::get_name_and_index;
22 use crate::task::config::{Action, TaskConfig};
23 use crate::task::ATOMIC_SERVICE;
24 
25 pub(crate) struct AttachedFiles {
26     pub(crate) files: Files,
27     pub(crate) sizes: Vec<i64>,
28     pub(crate) body_files: Files,
29 }
30 
31 impl AttachedFiles {
open(config: &TaskConfig) -> io::Result<AttachedFiles>32     pub(crate) fn open(config: &TaskConfig) -> io::Result<AttachedFiles> {
33         let tid = config.common_data.task_id;
34         let (files, sizes) = cvt_res_error!(
35             open_task_files(config),
36             "open task files failed - task_id: {}",
37             tid
38         );
39 
40         let body_files = cvt_res_error!(
41             open_body_files(config),
42             "open body files failed - task_id: {}",
43             tid
44         );
45 
46         Ok(Self {
47             files,
48             sizes,
49             body_files,
50         })
51     }
52 }
53 
open_task_files(config: &TaskConfig) -> io::Result<(Files, Vec<i64>)>54 fn open_task_files(config: &TaskConfig) -> io::Result<(Files, Vec<i64>)> {
55     let tid = config.common_data.task_id;
56     let uid = config.common_data.uid;
57     let bundle_name = convert_bundle_name(config);
58 
59     let mut files = Vec::new();
60     let mut sizes = Vec::new();
61 
62     for (idx, fs) in config.file_specs.iter().enumerate() {
63         match config.common_data.action {
64             Action::Upload => {
65                 let file = if fs.is_user_file {
66                     match fs.fd {
67                         Some(fd) => unsafe { File::from_raw_fd(fd) },
68                         None => {
69                             error!("None user file failed - task_id: {}, idx: {}", tid, idx);
70                             return Err(io::Error::new(io::ErrorKind::Other, "none user file"));
71                         }
72                     }
73                 } else {
74                     cvt_res_error!(
75                         open_file_readonly(uid, &bundle_name, &fs.path),
76                         "Open file RO failed - task_id: {}, idx: {}",
77                         tid,
78                         idx
79                     )
80                 };
81                 let size = cvt_res_error!(
82                     file.metadata().map(|data| data.len()),
83                     "Cannot get upload file's size - task_id: {}, idx: {}",
84                     tid,
85                     idx
86                 );
87                 files.push(AsyncFile::new(file));
88                 debug!(
89                     "Get file size succeed - task_id: {}, idx: {}, size: {}",
90                     tid, idx, size
91                 );
92                 sizes.push(size as i64);
93             }
94             Action::Download => {
95                 let file = if fs.is_user_file {
96                     match fs.fd {
97                         Some(fd) => unsafe { File::from_raw_fd(fd) },
98                         None => {
99                             error!("None user file failed - task_id: {}, idx: {}", tid, idx);
100                             return Err(io::Error::new(io::ErrorKind::Other, "none user file"));
101                         }
102                     }
103                 } else {
104                     cvt_res_error!(
105                         open_file_readwrite(uid, &bundle_name, &fs.path),
106                         "Open file RW failed - task_id: {}, idx: {}",
107                         tid,
108                         idx
109                     )
110                 };
111                 files.push(AsyncFile::new(file));
112                 sizes.push(-1)
113             }
114             _ => unreachable!("Action::Any in open_task_files should never reach"),
115         }
116     }
117     Ok((Files::new(files), sizes))
118 }
119 
open_body_files(config: &TaskConfig) -> io::Result<Files>120 fn open_body_files(config: &TaskConfig) -> io::Result<Files> {
121     let tid = config.common_data.task_id;
122     let uid = config.common_data.uid;
123     let bundle_name = convert_bundle_name(config);
124 
125     let mut body_files = Vec::new();
126     for (idx, path) in config.body_file_paths.iter().enumerate() {
127         let file = cvt_res_error!(
128             open_file_readwrite(uid, &bundle_name, path),
129             "Open body_file failed - task_id: {}, idx: {}",
130             tid,
131             idx
132         );
133         body_files.push(AsyncFile::new(file))
134     }
135     Ok(Files::new(body_files))
136 }
137 
open_file_readwrite(uid: u64, bundle_name: &str, path: &str) -> io::Result<File>138 fn open_file_readwrite(uid: u64, bundle_name: &str, path: &str) -> io::Result<File> {
139     Ok(cvt_res_error!(
140         OpenOptions::new()
141             .read(true)
142             .append(true)
143             .open(convert_path(uid, bundle_name, path)),
144         "open_file_readwrite failed"
145     ))
146 }
147 
open_file_readonly(uid: u64, bundle_name: &str, path: &str) -> io::Result<File>148 fn open_file_readonly(uid: u64, bundle_name: &str, path: &str) -> io::Result<File> {
149     Ok(cvt_res_error!(
150         OpenOptions::new()
151             .read(true)
152             .open(convert_path(uid, bundle_name, path)),
153         "open_file_readonly failed"
154     ))
155 }
156 
convert_path(uid: u64, bundle_name: &str, path: &str) -> String157 pub(crate) fn convert_path(uid: u64, bundle_name: &str, path: &str) -> String {
158     let uuid = uid / 200000;
159     let base_replace = format!("{}/base/{}", uuid, bundle_name);
160     let real_path = path
161         .replacen("storage", "app", 1)
162         .replacen("base", &base_replace, 1);
163     debug!("convert to real_path: {}", real_path);
164     real_path
165 }
166 
convert_bundle_name(config: &TaskConfig) -> String167 pub(crate) fn convert_bundle_name(config: &TaskConfig) -> String {
168     let is_account = config.bundle_type == ATOMIC_SERVICE;
169     let bundle_name = config.bundle.as_str();
170     if is_account {
171         let atomic_account = config.atomic_account.as_str();
172         format!("+auid-{}+{}", atomic_account, bundle_name)
173     } else {
174         let uid = config.common_data.uid;
175         check_app_clone_bundle_name(uid, bundle_name)
176     }
177 }
178 
check_app_clone_bundle_name(uid: u64, bundle_name: &str) -> String179 fn check_app_clone_bundle_name(uid: u64, bundle_name: &str) -> String {
180     let mut ret_name = bundle_name.to_string();
181     if let Some((index, name)) = get_name_and_index(uid as i32) {
182         if bundle_name != name {
183             info!("bundle name not matching. {:?}, {:?}", bundle_name, name);
184         }
185         if index > 0 {
186             ret_name = format!("+clone-{}+{}", index, bundle_name);
187         }
188     }
189     ret_name
190 }
191 
192 pub(crate) struct Files(UnsafeCell<Vec<AsyncFile>>);
193 
194 impl Files {
new(files: Vec<AsyncFile>) -> Self195     fn new(files: Vec<AsyncFile>) -> Self {
196         Self(UnsafeCell::new(files))
197     }
198 
len(&self) -> usize199     pub(crate) fn len(&self) -> usize {
200         unsafe { &*self.0.get() }.len()
201     }
202 
get(&self, index: usize) -> Option<&AsyncFile>203     pub(crate) fn get(&self, index: usize) -> Option<&AsyncFile> {
204         unsafe { &*self.0.get() }.get(index)
205     }
206 
get_mut(&self, index: usize) -> Option<&mut AsyncFile>207     pub(crate) fn get_mut(&self, index: usize) -> Option<&mut AsyncFile> {
208         unsafe { &mut *self.0.get() }.get_mut(index)
209     }
210 }
211 
212 unsafe impl Sync for Files {}
213 unsafe impl Send for Files {}
214