Finished the routine to print in size order.
[dus.git] / dus.c
1
2 /*
3  *  dus is a simple utility designed to display the list of files and
4  *  directories with disk occupancy, sorted according to it.
5  *
6  *  Copyright (c) 2009 Francois Fleuret
7  *  Written by Francois Fleuret <francois@fleuret.org>
8  *
9  *  This file is part of dus.
10  *
11  *  dus is free software: you can redistribute it and/or modify it
12  *  under the terms of the GNU General Public License version 3 as
13  *  published by the Free Software Foundation.
14  *
15  *  dus is distributed in the hope that it will be useful, but WITHOUT
16  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
18  *  License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with dus.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #define _BSD_SOURCE
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <dirent.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <string.h>
35
36 size_t file_or_dir_size(char *name) {
37   DIR *dir;
38   struct dirent *dir_e;
39   struct stat dummy;
40   size_t result;
41   char subname[1024];
42
43   result = 0;
44
45   if(lstat(name, &dummy) != 0) {
46     printf("Can not stat %s (%s).\n", name, strerror(errno));
47     exit (1);
48   }
49
50   if(S_ISLNK(dummy.st_mode)) {
51     return 0;
52   }
53
54   dir = opendir(name);
55
56   if(dir) {
57     while((dir_e = readdir(dir))) {
58       if(strcmp(dir_e->d_name, ".") &&
59          strcmp(dir_e->d_name, "..")) {
60         sprintf(subname, "%s/%s", name, dir_e->d_name);
61         result += file_or_dir_size(subname);
62       }
63     }
64     closedir(dir);
65   } else {
66     if(S_ISREG(dummy.st_mode)) {
67       result += dummy.st_size;
68     }
69   }
70
71   return result;
72 }
73
74 /**********************************************************************/
75
76 struct file_with_size {
77   char *filename;
78   size_t size;
79   struct file_with_size *next;
80 };
81
82 struct file_with_size *create(char *name, struct file_with_size *current) {
83   struct file_with_size *result;
84   result = malloc(sizeof(struct file_with_size));
85   result->filename = strdup(name);
86   result->size = file_or_dir_size(name);
87   result->next = current;
88   return result;
89 }
90
91 void destroy(struct file_with_size *node) {
92   struct file_with_size *next;
93   while(node) {
94     next = node->next;
95     free(node->filename);
96     free(node);
97     node = next;
98   }
99 }
100
101 /**********************************************************************/
102
103 int compare_files(const void *x1, const void *x2) {
104   const struct file_with_size **f1, **f2;
105
106   f1 = (const struct file_with_size **) x1;
107   f2 = (const struct file_with_size **) x2;
108
109   if((*f1)->size < (*f2)->size) {
110     return -1;
111   } else if((*f1)->size > (*f2)->size) {
112     return 1;
113   } else {
114     return 0;
115   }
116 }
117
118
119 void print_sorted(struct file_with_size *root) {
120   struct file_with_size *node;
121   struct file_with_size **nodes;
122   int nb, n;
123
124   nb = 0;
125   for(node = root; node; node = node->next) {
126     nb++;
127   }
128
129   nodes = malloc(nb * sizeof(struct file_with_size *));
130
131   n = 0;
132   for(node = root; node; node = node->next) {
133     nodes[n++] = node;
134   }
135
136   qsort(nodes, nb, sizeof(struct file_with_size *), compare_files);
137
138   for(n = 0; n < nb; n++) {
139     printf("%u %s\n", nodes[n]->size, nodes[n]->filename);
140   }
141
142   free(nodes);
143 }
144
145 /**********************************************************************/
146
147 int main(int argc, char **argv) {
148   int k;
149   struct file_with_size *root;
150
151   root = 0;
152   for(k = 1; k < argc; k++) {
153     root = create(argv[k], root);
154   }
155
156   print_sorted(root);
157
158   destroy(root);
159
160   exit(0);
161 }