• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #include "mtpfs_util.h"
17 
18 #include <config.h>
19 #include <cstdio>
20 #include <cstring>
21 #include <iomanip>
22 #include <sstream>
23 
24 #include <dirent.h>
25 #include <libgen.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <climits>
30 #include <libmtp.h>
31 #include <libusb.h>
32 
33 #include "file_utils.h"
34 #include "storage_service_log.h"
35 
36 constexpr const char *DEV_NULL = "/dev/null";
37 constexpr int32_t MAX_INT = 255;
38 constexpr int32_t SCANF_NUM = 2;
39 
40 bool MtpFsUtil::enabled_ = false;
41 int MtpFsUtil::stdOut_ = -1;
42 int MtpFsUtil::stdErr_ = -1;
43 
On()44 void MtpFsUtil::On()
45 {
46     if (!enabled_) {
47         return;
48     }
49     if (freopen(DEV_NULL, "w", stdout) == nullptr) {
50         LOGE("freopen stdout fail");
51     }
52     if (freopen(DEV_NULL, "w", stderr) == nullptr) {
53         LOGE("freopen stderr fail");
54     }
55     dup2(stdOut_, fileno(stdout));
56     dup2(stdErr_, fileno(stderr));
57     close(stdOut_);
58     close(stdErr_);
59     if (setvbuf(stdout, NULL, _IOLBF, 0) != 0) {
60         LOGE("setvbuf stdout fail");
61     }
62     if (setvbuf(stderr, NULL, _IOLBF, 0) != 0) {
63         LOGE("setvbuf stderr fail");
64     }
65     enabled_ = false;
66 }
67 
Off()68 void MtpFsUtil::Off()
69 {
70     if (enabled_) {
71         return;
72     }
73     fflush(stdout);
74     fflush(stderr);
75     stdOut_ = dup(fileno(stdout));
76     stdErr_ = dup(fileno(stderr));
77     if (freopen(DEV_NULL, "w", stdout) == nullptr) {
78         LOGE("freopen stdout fail");
79     }
80     if (freopen(DEV_NULL, "w", stderr) == nullptr) {
81         LOGE("freopen stderr fail");
82     }
83     enabled_ = true;
84 }
85 
SmtpfsDirName(const std::string & path)86 std::string SmtpfsDirName(const std::string &path)
87 {
88     char *str = strdup(path.c_str());
89     if (!str) {
90         return -ENOMEM;
91     }
92     std::string result(dirname(str));
93     free(static_cast<void *>(str));
94     return result;
95 }
96 
SmtpfsBaseName(const std::string & path)97 std::string SmtpfsBaseName(const std::string &path)
98 {
99     char *str = strdup(path.c_str());
100     if (!str) {
101         return -ENOMEM;
102     }
103     std::string result(basename(str));
104     free(static_cast<void *>(str));
105     return result;
106 }
107 
SmtpfsRealPath(const std::string & path)108 std::string SmtpfsRealPath(const std::string &path)
109 {
110     if (path.length() > PATH_MAX) {
111         return "";
112     }
113     char buf[PATH_MAX + 1];
114     char *realPath = realpath(path.c_str(), buf);
115     return std::string(realPath ? buf : "");
116 }
117 
SmtpfsGetTmpDir()118 std::string SmtpfsGetTmpDir()
119 {
120     const char *cTmp = "/data/local/mtp_tmp";
121     OHOS::StorageDaemon::DelTemp(cTmp);
122     std::string tmpDir = SmtpfsRealPath(cTmp) + "/simple-mtpfs-XXXXXX";
123     char *cTempDir = ::strdup(tmpDir.c_str());
124     if (cTempDir == nullptr) {
125         return "";
126     }
127     char *cTmpDir = ::mkdtemp(cTempDir);
128     if (cTmpDir == nullptr) {
129         ::free(cTempDir);
130         return "";
131     }
132     tmpDir.assign(cTmpDir);
133     ::free(static_cast<void *>(cTempDir));
134     return tmpDir;
135 }
136 
SmtpfsCreateDir(const std::string & dirName)137 bool SmtpfsCreateDir(const std::string &dirName)
138 {
139     return ::mkdir(dirName.c_str(), S_IRWXU) == 0;
140 }
141 
SmtpfsRemoveDir(const std::string & dirName)142 bool SmtpfsRemoveDir(const std::string &dirName)
143 {
144     DIR *dir;
145     struct dirent *entry;
146     std::string path;
147 
148     dir = ::opendir(dirName.c_str());
149     if (dir == nullptr) {
150         return false;
151     }
152     while ((entry = ::readdir(dir))) {
153         if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
154             path = dirName + "/" + entry->d_name;
155             if (entry->d_type == DT_DIR) {
156                 ::closedir(dir);
157                 return SmtpfsRemoveDir(path);
158             }
159             ::unlink(path.c_str());
160         }
161     }
162     ::closedir(dir);
163     ::remove(dirName.c_str());
164     return true;
165 }
166 
SmtpfsUsbDevPath(const std::string & path,uint8_t * bnum,uint8_t * dnum)167 bool SmtpfsUsbDevPath(const std::string &path, uint8_t *bnum, uint8_t *dnum)
168 {
169     unsigned int bus;
170     unsigned int dev;
171 #ifdef USB_DEVPATH
172     std::string realPath(SmtpfsRealPath(path));
173     if (realPath.empty() || sscanf_s(realPath.c_str(), USB_DEVPATH, &bus, &dev) != SCANF_NUM) {
174 #endif
175         if (sscanf_s(path.c_str(), "%u/%u", &bus, &dev) != SCANF_NUM) {
176             return false;
177         }
178     }
179     if (bus > MAX_INT || dev > MAX_INT) {
180         return false;
181     }
182 
183     *bnum = bus;
184     *dnum = dev;
185     return true;
186 }
187 
smtpfs_raw_device_new_priv(libusb_device * usb_device)188 LIBMTP_raw_device_t *smtpfs_raw_device_new_priv(libusb_device *usb_device)
189 {
190     if (!usb_device) {
191         return nullptr;
192     }
193 
194     LIBMTP_raw_device_t *device = static_cast<LIBMTP_raw_device_t *>(malloc(sizeof(LIBMTP_raw_device_t)));
195 
196     if (device == nullptr) {
197         return nullptr;
198     }
199 
200     struct libusb_device_descriptor desc;
201     int err = libusb_get_device_descriptor(usb_device, &desc);
202     if (err != LIBUSB_SUCCESS) {
203         free(static_cast<void *>(device));
204         return nullptr;
205     }
206 
207     device->device_entry.vendor = nullptr;
208     device->device_entry.vendor_id = desc.idVendor;
209     device->device_entry.product = nullptr;
210     device->device_entry.product_id = desc.idProduct;
211     device->device_entry.device_flags = 0;
212 
213     device->bus_location = static_cast<uint32_t>(libusb_get_bus_number(usb_device));
214     device->devnum = libusb_get_device_address(usb_device);
215 
216     return device;
217 }
218 
SmtpfsRawDeviceNew(const std::string & path)219 LIBMTP_raw_device_t *SmtpfsRawDeviceNew(const std::string &path)
220 {
221     uint8_t bnum;
222     uint8_t dnum;
223     if (!SmtpfsUsbDevPath(path, &bnum, &dnum)) {
224         return nullptr;
225     }
226 
227     if (libusb_init(NULL) != 0) {
228         return nullptr;
229     }
230 
231     libusb_device **devList;
232     ssize_t numDevs = libusb_get_device_list(NULL, &devList);
233     if (!numDevs) {
234         libusb_exit(NULL);
235         return nullptr;
236     }
237 
238     libusb_device *dev = nullptr;
239     for (auto i = 0; i < numDevs; ++i) {
240         dev = devList[i];
241         if (bnum == libusb_get_bus_number(devList[i]) && dnum == libusb_get_device_address(devList[i])) {
242             break;
243         }
244         dev = nullptr;
245     }
246 
247     LIBMTP_raw_device_t *rawDevice = smtpfs_raw_device_new_priv(dev);
248 
249     libusb_free_device_list(devList, 0);
250     libusb_exit(NULL);
251 
252     return rawDevice;
253 }
254 
SmtpfsResetDevice(LIBMTP_raw_device_t * device)255 bool SmtpfsResetDevice(LIBMTP_raw_device_t *device)
256 {
257     if (device == nullptr) {
258         LOGE("device is null");
259         return false;
260     }
261 
262     if (libusb_init(NULL) != 0) {
263         return false;
264     }
265 
266     libusb_device **devList;
267     ssize_t numDevs = libusb_get_device_list(NULL, &devList);
268     if (!numDevs) {
269         libusb_exit(NULL);
270         return false;
271     }
272 
273     libusb_device_handle *devHandle = nullptr;
274     for (auto i = 0; i < numDevs; ++i) {
275         uint8_t bnum = libusb_get_bus_number(devList[i]);
276         uint8_t dnum = libusb_get_device_address(devList[i]);
277         if (static_cast<uint32_t>(bnum) == device->bus_location && dnum == device->devnum) {
278             libusb_open(devList[i], &devHandle);
279             libusb_reset_device(devHandle);
280             libusb_close(devHandle);
281             break;
282         }
283     }
284 
285     libusb_free_device_list(devList, 0);
286     libusb_exit(NULL);
287 
288     return true;
289 }
290 
SmtpfsRawDeviceFree(LIBMTP_raw_device_t * device)291 void SmtpfsRawDeviceFree(LIBMTP_raw_device_t *device)
292 {
293     if (device == nullptr) {
294         return;
295     }
296 
297     free(static_cast<void *>(device->device_entry.vendor));
298     free(static_cast<void *>(device->device_entry.product));
299     free(static_cast<void *>(device));
300 }
301 
SmtpfsCheckDir(const std::string & path)302 bool SmtpfsCheckDir(const std::string &path)
303 {
304     struct stat buf;
305     if (::stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode) && ::access(path.c_str(), R_OK | W_OK | X_OK) == 0) {
306         return true;
307     }
308 
309     return false;
310 }
311