133b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root/*
233b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root *
333b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root * Copyright (C) 2008, The Android Open Source Project
433b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root *
533b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root * Licensed under the Apache License, Version 2.0 (the "License");
633b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root * you may not use this file except in compliance with the License.
733b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root * You may obtain a copy of the License at
833b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root *
933b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root *     http://www.apache.org/licenses/LICENSE-2.0
1033b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root *
1133b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root * Unless required by applicable law or agreed to in writing, software
1233b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root * distributed under the License is distributed on an "AS IS" BASIS,
1333b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1433b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root * See the License for the specific language governing permissions and
1533b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root * limitations under the License.
1633b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root */
1733b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root
1833b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root#include <dirent.h>
1933b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root#include <fcntl.h>
2033b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root#include <sys/stat.h>
2133b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root
2233b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root#include <diskusage/dirsize.h>
2333b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root
2433b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Rootint64_t stat_size(struct stat *s)
2533b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root{
2633b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    int64_t blksize = s->st_blksize;
2733b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    int64_t size = s->st_size;
2833b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root
2933b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    if (blksize) {
3033b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root        /* round up to filesystem block size */
3133b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root        size = (size + blksize - 1) & (~(blksize - 1));
3233b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    }
3333b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root
3433b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    return size;
3533b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root}
3633b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root
3733b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Rootint64_t calculate_dir_size(int dfd)
3833b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root{
3933b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    int64_t size = 0;
4033b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    struct stat s;
4133b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    DIR *d;
4233b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    struct dirent *de;
4333b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root
4433b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    d = fdopendir(dfd);
4533b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    if (d == NULL) {
4633b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root        close(dfd);
4733b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root        return 0;
4833b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    }
4933b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root
5033b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    while ((de = readdir(d))) {
5133b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root        const char *name = de->d_name;
5233b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root        if (de->d_type == DT_DIR) {
5333b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root            int subfd;
5433b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root
5533b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root            /* always skip "." and ".." */
5633b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root            if (name[0] == '.') {
5733b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root                if (name[1] == 0)
5833b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root                    continue;
5933b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root                if ((name[1] == '.') && (name[2] == 0))
6033b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root                    continue;
6133b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root            }
6233b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root
6333b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
6433b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root            if (subfd >= 0) {
6533b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root                size += calculate_dir_size(subfd);
6633b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root            }
6733b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root        } else {
6833b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root            if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
6933b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root                size += stat_size(&s);
7033b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root            }
7133b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root        }
7233b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    }
7333b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    closedir(d);
7433b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root    return size;
7533b2264ea9ab0f1980c49698729a0ab3c51d07feKenny Root}
76