Exemple #1
0
status_t MediaScanner::doProcessDirectory(
        char *path, int pathRemaining, const char *extensions,
        MediaScannerClient &client, ExceptionCheck exceptionCheck,
        void *exceptionEnv) {
    // place to copy file or directory name
    char* fileSpot = path + strlen(path);
    struct dirent* entry;
    char* tempPathBuffer = NULL;
    char* pathBuffer = NULL;
    DIR* dir = NULL;
    int pathLength = strlen(path);
    if (pathLength >= PATH_MAX) {
        goto failure;
    }
    pathBuffer = (char *)malloc(PATH_MAX + 1);
    tempPathBuffer = (char *)malloc(PATH_MAX + 1);
    if (!pathBuffer || !tempPathBuffer) {
        goto failure;
    }

    strcpy(pathBuffer, path);
    // ignore directories that contain a  ".nomedia" file
    if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
        strcpy(fileSpot, ".nomedia");
        if (access(path, F_OK) == 0) {
            LOGD("found .nomedia, skipping directory\n");
            fileSpot[0] = 0;
            client.addNoMediaFolder(path);
            goto success;
        }
        // restore path
        fileSpot[0] = 0;
    }

    dir = opendir(path);
    if (!dir) {
        LOGD("opendir %s failed, errno: %d", path, errno);
        goto failure;
    }

    while ((entry = readdir(dir))) {
        const char* name = entry->d_name;

        // ignore "." and ".."
        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
            continue;
        }

        int type = entry->d_type;
        if (type == DT_UNKNOWN) {
            // If the type is unknown, stat() the file instead.
            // This is sometimes necessary when accessing NFS mounted filesystems, but
            // could be needed in other cases well.
            struct stat statbuf;
            int tempPathLength = strlen(pathBuffer) + strlen(name);
            if (tempPathLength >= PATH_MAX) {
                goto failure;
            }

            strcpy(tempPathBuffer, pathBuffer);
            strcat(tempPathBuffer, name);
            if (stat(tempPathBuffer, &statbuf) == 0) {
                if (S_ISREG(statbuf.st_mode)) {
                    type = DT_REG;
                } else if (S_ISDIR(statbuf.st_mode)) {
                    type = DT_DIR;
                }
            } else {
                LOGD("stat() failed for %s %s: %s", path, name, strerror(errno) );
            }

        }
        if (type == DT_REG || type == DT_DIR) {
            int nameLength = strlen(name);
            bool isDirectory = (type == DT_DIR);

            if (nameLength > pathRemaining || (isDirectory && nameLength + 1 > pathRemaining)) {
                // path too long!
                continue;
            }

            strcpy(fileSpot, name);
            if (isDirectory) {
                // ignore directories with a name that starts with '.'
                // for example, the Mac ".Trashes" directory
                if (name[0] == '.') continue;

                strcat(fileSpot, "/");
                int err = doProcessDirectory(path, pathRemaining - nameLength - 1, extensions, client, exceptionCheck, exceptionEnv);
                if (err) {
                    // pass exceptions up - ignore other errors
                    if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
                    LOGE("Error processing '%s' - skipping\n", path);
                    continue;
                }
            } else if (fileMatchesExtension(path, extensions)) {
                struct stat statbuf;
                stat(path, &statbuf);
                if (statbuf.st_size > 0) {
                    client.scanFile(path, statbuf.st_mtime, statbuf.st_size);
                }
                if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
            }
        }
    }
    closedir(dir);
success:
    free(pathBuffer);
    free(tempPathBuffer);
    return OK;
failure:
    free(pathBuffer);
    free(tempPathBuffer);
    closedir(dir);
    return -1;
}