MtpStorage.cpp revision 16864bae0f51c32c456da2c43adf7a057c0c4882
1/*
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}
136