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