blob: 2c5e23bf660c9e184d463e270e33be03acf11db9 [file] [log] [blame]
Mike Lockwood5fd1ff02010-07-26 20:44:42 -04001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <unistd.h>
18#include <stdio.h>
19#include <string.h>
20#include <stdlib.h>
21
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <fcntl.h>
25
26#if HAVE_READLINE
27#include <readline/readline.h>
28#include <readline/history.h>
29#endif
30
31#include "MtpClient.h"
32#include "MtpDevice.h"
33#include "MtpObjectInfo.h"
34
35#include "MtpFile.h"
36
37#define PROMPT "mtp> "
38
39using namespace android;
40
41static MtpClient* sClient = NULL;
42
43// current working directory information for interactive shell
44static MtpFile* sCurrentDirectory = NULL;
45
46static MtpFile* parse_path(char* path) {
47 return MtpFile::parsePath(sCurrentDirectory, path);
48}
49
50class MyClient : public MtpClient {
51private:
52 virtual void deviceAdded(MtpDevice *device) {
53 }
54
55 virtual void deviceRemoved(MtpDevice *device) {
56 }
57
58public:
59};
60
61static void init() {
62 sClient = new MyClient;
63 sClient->start();
64 MtpFile::init(sClient);
65}
66
67static int set_cwd(int argc, char* argv[]) {
68 if (argc != 1) {
69 fprintf(stderr, "cd should have one argument\n");
70 return -1;
71 }
72 if (!strcmp(argv[0], "/")) {
73 delete sCurrentDirectory;
74 sCurrentDirectory = NULL;
75 }
76 else {
77 MtpFile* file = parse_path(argv[0]);
78 if (file) {
79 delete sCurrentDirectory;
80 sCurrentDirectory = file;
81 } else {
82 fprintf(stderr, "could not find %s\n", argv[0]);
83 return -1;
84 }
85 }
86 return 0;
87}
88
89static void list_devices() {
90 // TODO - need to make sure the list will not change while iterating
91 MtpDeviceList& devices = sClient->getDeviceList();
92 for (int i = 0; i < devices.size(); i++) {
93 MtpDevice* device = devices[i];
94 MtpFile* file = new MtpFile(device);
95 file->print();
96 delete file;
97 }
98}
99
100static int list(int argc, char* argv[]) {
101 if (argc == 0) {
102 // list cwd
103 if (sCurrentDirectory) {
104 sCurrentDirectory->list();
105 } else {
106 list_devices();
107 }
108 }
109
110 for (int i = 0; i < argc; i++) {
111 char* path = argv[i];
112 if (!strcmp(path, "/")) {
113 list_devices();
114 } else {
115 MtpFile* file = parse_path(path);
116 if (!file) {
117 fprintf(stderr, "could not find %s\n", path);
118 return -1;
119 }
120 file->list();
121 }
122 }
123
124 return 0;
125}
126
127static int get_file(int argc, char* argv[]) {
128 int ret = -1;
129 int srcFD = -1;
130 int destFD = -1;
131 MtpFile* srcFile = NULL;
132 MtpObjectInfo* info = NULL;
133 char* dest;
134
135 if (argc < 1) {
136 fprintf(stderr, "not enough arguments\n");
137 return -1;
138 } else if (argc > 2) {
139 fprintf(stderr, "too many arguments\n");
140 return -1;
141 }
142
143 // find source object
144 char* src = argv[0];
145 srcFile = parse_path(src);
146 if (!srcFile) {
147 fprintf(stderr, "could not find %s\n", src);
148 return -1;
149 }
150 info = srcFile->getObjectInfo();
151 if (!info) {
152 fprintf(stderr, "could not find object info for %s\n", src);
153 goto fail;
154 }
155 if (info->mFormat == MTP_FORMAT_ASSOCIATION) {
156 fprintf(stderr, "copying directories not implemented yet\n");
157 goto fail;
158 }
159
160 dest = (argc > 1 ? argv[1] : info->mName);
161 destFD = open(dest, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
162 if (destFD < 0) {
163 fprintf(stderr, "could not create %s\n", dest);
164 goto fail;
165 }
166 srcFD = srcFile->getDevice()->readObject(info->mHandle, info->mCompressedSize);
167 if (srcFD < 0)
168 goto fail;
169
170 char buffer[65536];
171 while (1) {
172 int count = read(srcFD, buffer, sizeof(buffer));
173 if (count <= 0)
174 break;
175 write(destFD, buffer, count);
176 }
177 // FIXME - error checking and reporting
178 ret = 0;
179
180fail:
181 delete srcFile;
182 delete info;
183 if (srcFD >= 0)
184 close(srcFD);
185 if (destFD >= 0)
186 close(destFD);
187 return ret;
188}
189
190static int put_file(int argc, char* argv[]) {
191 int ret = -1;
192 int srcFD = -1;
193 MtpFile* destFile = NULL;
194 MtpObjectInfo* srcInfo = NULL;
195 MtpObjectInfo* destInfo = NULL;
196 MtpObjectHandle handle;
197 struct stat statbuf;
198 const char* lastSlash;
199
200 if (argc < 1) {
201 fprintf(stderr, "not enough arguments\n");
202 return -1;
203 } else if (argc > 2) {
204 fprintf(stderr, "too many arguments\n");
205 return -1;
206 }
207 const char* src = argv[0];
208 srcFD = open(src, O_RDONLY);
209 if (srcFD < 0) {
210 fprintf(stderr, "could not open %s\n", src);
211 goto fail;
212 }
213 if (argc == 2) {
214 char* dest = argv[1];
215 destFile = parse_path(dest);
216 if (!destFile) {
217 fprintf(stderr, "could not find %s\n", dest);
218 goto fail;
219 }
220 } else {
221 if (!sCurrentDirectory) {
222 fprintf(stderr, "current working directory not set\n");
223 goto fail;
224 }
225 destFile = new MtpFile(sCurrentDirectory);
226 }
227
228 destInfo = destFile->getObjectInfo();
229 if (!destInfo) {
230 fprintf(stderr, "could not find object info destination directory\n");
231 goto fail;
232 }
233 if (destInfo->mFormat != MTP_FORMAT_ASSOCIATION) {
234 fprintf(stderr, "destination not a directory\n");
235 goto fail;
236 }
237
238 if (fstat(srcFD, &statbuf))
239 goto fail;
240
241 srcInfo = new MtpObjectInfo(0);
242 srcInfo->mStorageID = destInfo->mStorageID;
243 srcInfo->mFormat = MTP_FORMAT_EXIF_JPEG; // FIXME
244 srcInfo->mCompressedSize = statbuf.st_size;
245 srcInfo->mParent = destInfo->mHandle;
246 lastSlash = strrchr(src, '/');
247 srcInfo->mName = strdup(lastSlash ? lastSlash + 1 : src);
248 srcInfo->mDateModified = statbuf.st_mtime;
249 handle = destFile->getDevice()->sendObjectInfo(srcInfo);
250 if (handle <= 0) {
251 printf("sendObjectInfo returned %04X\n", handle);
252 goto fail;
253 }
254 if (destFile->getDevice()->sendObject(srcInfo, srcFD))
255 ret = 0;
256
257fail:
258 delete destFile;
259 delete srcInfo;
260 delete destInfo;
261 if (srcFD >= 0)
262 close(srcFD);
263 printf("returning %d\n", ret);
264 return ret;
265}
266
267typedef int (* command_func)(int argc, char* argv[]);
268
269struct command_table_entry {
270 const char* name;
271 command_func func;
272};
273
274const command_table_entry command_list[] = {
275 { "cd", set_cwd },
276 { "ls", list },
277 { "get", get_file },
278 { "put", put_file },
279 { NULL, NULL },
280};
281
282
283static int do_command(int argc, char* argv[]) {
284 const command_table_entry* command = command_list;
285 const char* name = *argv++;
286 argc--;
287
288 while (command->name) {
289 if (!strcmp(command->name, name))
290 return command->func(argc, argv);
291 else
292 command++;
293 }
294 fprintf(stderr, "unknown command %s\n", name);
295 return -1;
296}
297
298static int shell() {
299 int argc;
300 int result = 0;
301#define MAX_ARGS 100
302 char* argv[MAX_ARGS];
303
304#if HAVE_READLINE
305 using_history();
306#endif
307
308 while (1) {
309#if HAVE_READLINE
310 char* line = readline(PROMPT);
311 if (!line) {
312 printf("\n");
313 exit(0);
314 }
315#else
316 char buffer[1000];
317 printf("%s", PROMPT);
318 char* line = NULL;
319 size_t length = 0;
320
321 buffer[0] = 0;
322 fgets(buffer, sizeof(buffer), stdin);
323 int count = strlen(buffer);
324 if (count > 0 && buffer[0] == EOF) {
325 printf("\n");
326 exit(0);
327 }
328 if (count > 0 && line[count - 1] == '\n')
329 line[count - 1] == 0;
330#endif
331 char* tok = strtok(line, " \t\n\r");
332 if (!tok)
333 continue;
334 if (!strcmp(tok, "quit") || !strcmp(tok, "exit")) {
335 exit(0);
336 }
337#if HAVE_READLINE
338 add_history(line);
339#endif
340 argc = 0;
341 while (tok) {
342 if (argc + 1 == MAX_ARGS) {
343 fprintf(stderr, "too many arguments\n");
344 result = -1;
345 goto bottom_of_loop;
346 }
347
348 argv[argc++] = strdup(tok);
349 tok = strtok(NULL, " \t\n\r");
350 }
351
352 result = do_command(argc, argv);
353
354bottom_of_loop:
355 for (int i = 0; i < argc; i++)
356 free(argv[i]);
357 free(line);
358 }
359
360 return result;
361}
362
363int main(int argc, char* argv[]) {
364 init();
365
366 if (argc == 1)
367 return shell();
368 else
369 return do_command(argc - 1, argv + 1);
370}