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