blob: bbdef51504677459058d378f387a5a655c3bb310 [file] [log] [blame]
Mike Lockwood56118b52010-05-11 17:16:59 -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 "MtpDatabase.h"
18#include "MtpStorage.h"
19
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <sys/statfs.h>
23#include <unistd.h>
24#include <dirent.h>
25#include <errno.h>
26#include <string.h>
27#include <stdio.h>
28#include <limits.h>
29
30
31MtpStorage::MtpStorage(MtpStorageID id, const char* filePath, MtpDatabase* db)
32 : mStorageID(id),
33 mFilePath(filePath),
34 mDatabase(db),
35 mMaxCapacity(0)
36{
37}
38
39MtpStorage::~MtpStorage() {
40}
41
42int MtpStorage::getType() const {
43 return MTP_STORAGE_FIXED_RAM;
44}
45
46int MtpStorage::getFileSystemType() const {
47 return MTP_STORAGE_FILESYSTEM_HIERARCHICAL;
48}
49
50int MtpStorage::getAccessCapability() const {
51 return MTP_STORAGE_READ_WRITE;
52}
53
54uint64_t MtpStorage::getMaxCapacity() {
55 if (mMaxCapacity == 0) {
56 struct statfs stat;
57 if (statfs(mFilePath, &stat))
58 return -1;
59 mMaxCapacity = (uint64_t)stat.f_blocks * (uint64_t)stat.f_bsize;
60 }
61 return mMaxCapacity;
62}
63
64uint64_t MtpStorage::getFreeSpace() {
65 struct statfs stat;
66 if (statfs(mFilePath, &stat))
67 return -1;
68 return (uint64_t)stat.f_bavail * (uint64_t)stat.f_bsize;
69}
70
71const char* MtpStorage::getDescription() const {
72 return "Phone Storage";
73}
74
75bool MtpStorage::scanFiles() {
76 mDatabase->beginTransaction();
77 int ret = scanDirectory(mFilePath, MTP_PARENT_ROOT);
78 mDatabase->commitTransaction();
79 return (ret == 0);
80}
81
82int MtpStorage::scanDirectory(const char* path, MtpObjectHandle parent)
83{
84 char buffer[PATH_MAX];
85 struct dirent* entry;
86
87 int length = strlen(path);
88 if (length > sizeof(buffer) + 2) {
89 fprintf(stderr, "path too long: %s\n", path);
90 }
91
92 DIR* dir = opendir(path);
93 if (!dir) {
94 fprintf(stderr, "opendir %s failed, errno: %d", path, errno);
95 return -1;
96 }
97
98 strncpy(buffer, path, sizeof(buffer));
99 char* fileStart = buffer + length;
100 // make sure we have a trailing slash
101 if (fileStart[-1] != '/') {
102 *(fileStart++) = '/';
103 }
104 int fileNameLength = sizeof(buffer) + fileStart - buffer;
105
106 while ((entry = readdir(dir))) {
107 const char* name = entry->d_name;
108
109 // ignore "." and "..", as well as any files or directories staring with dot
110 if (name[0] == '.') {
111 continue;
112 }
113 if (strlen(name) + 1 > fileNameLength) {
114 fprintf(stderr, "path too long for %s\n", name);
115 continue;
116 }
117 strcpy(fileStart, name);
118
119 struct stat statbuf;
120 memset(&statbuf, 0, sizeof(statbuf));
121 stat(buffer, &statbuf);
122
123 if (entry->d_type == DT_DIR) {
124 MtpObjectHandle handle = mDatabase->addFile(buffer, MTP_FORMAT_ASSOCIATION,
125 parent, mStorageID, 0, 0, statbuf.st_mtime);
126 scanDirectory(buffer, handle);
127 } else if (entry->d_type == DT_REG) {
128 mDatabase->addFile(buffer, MTP_FORMAT_UNDEFINED, parent, mStorageID,
129 statbuf.st_size, 0, statbuf.st_mtime);
130 }
131 }
132
133 closedir(dir);
134 return 0;
135}