1/*  Copyright 1997,2000-2002,2009 Alain Knaff.
2 *  This file is part of mtools.
3 *
4 *  Mtools is free software: you can redistribute it and/or modify
5 *  it under the terms of the GNU General Public License as published by
6 *  the Free Software Foundation, either version 3 of the License, or
7 *  (at your option) any later version.
8 *
9 *  Mtools is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *  GNU General Public License for more details.
13 *
14 *  You should have received a copy of the GNU General Public License
15 *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16 *
17 * mdu.c:
18 * Display the space occupied by an MSDOS directory
19 */
20
21#include "sysincludes.h"
22#include "msdos.h"
23#include "vfat.h"
24#include "mtools.h"
25#include "file.h"
26#include "mainloop.h"
27#include "fs.h"
28#include "codepage.h"
29
30
31typedef struct Arg_t {
32	int all;
33	int inDir;
34	int summary;
35	struct Arg_t *parent;
36	char *target;
37	char *path;
38	unsigned int blocks;
39	MainParam_t mp;
40} Arg_t;
41
42static void usage(int ret) NORETURN;
43static void usage(int ret)
44{
45		fprintf(stderr, "Mtools version %s, dated %s\n",
46			mversion, mdate);
47		fprintf(stderr, "Usage: %s: msdosdirectory\n",
48			progname);
49		exit(ret);
50}
51
52static int file_mdu(direntry_t *entry, MainParam_t *mp)
53{
54	unsigned int blocks;
55	Arg_t * arg = (Arg_t *) (mp->arg);
56
57	blocks = countBlocks(entry->Dir,getStart(entry->Dir, &entry->dir));
58	if(arg->all || !arg->inDir) {
59		fprintPwd(stdout, entry,0);
60		printf(" %d\n", blocks);
61	}
62	arg->blocks += blocks;
63	return GOT_ONE;
64}
65
66
67static int dir_mdu(direntry_t *entry, MainParam_t *mp)
68{
69	Arg_t *parentArg = (Arg_t *) (mp->arg);
70	Arg_t arg;
71	int ret;
72
73	arg = *parentArg;
74	arg.mp.arg = (void *) &arg;
75	arg.parent = parentArg;
76	arg.inDir = 1;
77
78	/* account for the space occupied by the directory itself */
79	if(!isRootDir(entry->Dir)) {
80		arg.blocks = countBlocks(entry->Dir,
81					 getStart(entry->Dir, &entry->dir));
82	} else {
83		arg.blocks = 0;
84	}
85
86	/* recursion */
87	ret = mp->loop(mp->File, &arg.mp, "*");
88	if(!arg.summary || !parentArg->inDir) {
89		fprintPwd(stdout, entry,0);
90		printf(" %d\n", arg.blocks);
91	}
92	arg.parent->blocks += arg.blocks;
93	return ret;
94}
95
96void mdu(int argc, char **argv, int type)
97{
98	Arg_t arg;
99	int c;
100
101	arg.all = 0;
102	arg.inDir = 0;
103	arg.summary = 0;
104	if(helpFlag(argc, argv))
105		usage(0);
106	while ((c = getopt(argc, argv, "i:ash")) != EOF) {
107		switch (c) {
108			case 'i':
109				set_cmd_line_image(optarg, 0);
110				break;
111			case 'a':
112				arg.all = 1;
113				break;
114			case 's':
115				arg.summary = 1;
116				break;
117			case 'h':
118				usage(0);
119			case '?':
120				usage(1);
121		}
122	}
123
124	if (optind >= argc)
125		usage(1);
126
127	if(arg.summary && arg.all) {
128		fprintf(stderr,"-a and -s options are mutually exclusive\n");
129		usage(1);
130	}
131
132	init_mp(&arg.mp);
133	arg.mp.callback = file_mdu;
134	arg.mp.openflags = O_RDONLY;
135	arg.mp.dirCallback = dir_mdu;
136
137	arg.mp.arg = (void *) &arg;
138	arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS;
139	exit(main_loop(&arg.mp, argv + optind, argc - optind));
140}
141