1/*  Copyright 1986-1992 Emmet P. Gray.
2 *  Copyright 1996-1998,2000-2002,2007,2009 Alain Knaff.
3 *  This file is part of mtools.
4 *
5 *  Mtools is free software: you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation, either version 3 of the License, or
8 *  (at your option) any later version.
9 *
10 *  Mtools is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 * mattrib.c
19 * Change MSDOS file attribute flags
20 */
21
22#include "sysincludes.h"
23#include "msdos.h"
24#include "mtools.h"
25#include "mainloop.h"
26
27typedef struct Arg_t {
28	char add;
29	unsigned char remove;
30	struct MainParam_t mp;
31	int recursive;
32	int doPrintName;
33} Arg_t;
34
35static int attrib_file(direntry_t *entry, MainParam_t *mp)
36{
37	Arg_t *arg=(Arg_t *) mp->arg;
38
39	if(entry->entry != -3) {
40		/* if not root directory, change it */
41		entry->dir.attr = (entry->dir.attr & arg->remove) | arg->add;
42		dir_write(entry);
43	}
44	return GOT_ONE;
45}
46
47static int replay_attrib(direntry_t *entry, MainParam_t *mp)
48{
49	if ( (IS_ARCHIVE(entry) && IS_DIR(entry)) ||
50		 (!IS_ARCHIVE(entry) && !IS_DIR(entry)) ||
51		 IS_SYSTEM(entry) || IS_HIDDEN(entry)) {
52
53		printf("mattrib ");
54
55		if (IS_ARCHIVE(entry) && IS_DIR(entry)) {
56			printf("+a ");
57		}
58
59		if (!IS_ARCHIVE(entry) && !IS_DIR(entry)) {
60			printf("-a ");
61		}
62
63		if (IS_SYSTEM(entry)) {
64			printf("+s ");
65		}
66
67		if (IS_HIDDEN(entry)) {
68			printf("+h ");
69		}
70
71		fprintPwd(stdout, entry, 1);
72		printf("\n");
73	}
74	return GOT_ONE;
75}
76
77
78
79static int view_attrib(direntry_t *entry, MainParam_t *mp)
80{
81	printf("  ");
82	if(IS_ARCHIVE(entry))
83		putchar('A');
84	else
85		putchar(' ');
86	fputs("  ",stdout);
87	if(IS_SYSTEM(entry))
88		putchar('S');
89	else
90		putchar(' ');
91	if(IS_HIDDEN(entry))
92		putchar('H');
93	else
94		putchar(' ');
95	if(IS_READONLY(entry))
96		putchar('R');
97	else
98		putchar(' ');
99	printf("     ");
100	fprintPwd(stdout, entry, 0);
101	printf("\n");
102	return GOT_ONE;
103}
104
105
106static int concise_view_attrib(direntry_t *entry, MainParam_t *mp)
107{
108	Arg_t *arg=(Arg_t *) mp->arg;
109
110	if(IS_ARCHIVE(entry))
111		putchar('A');
112	if(IS_DIR(entry))
113		putchar('D');
114	if(IS_SYSTEM(entry))
115		putchar('S');
116	if(IS_HIDDEN(entry))
117		putchar('H');
118	if(IS_READONLY(entry))
119		putchar('R');
120	if(arg->doPrintName) {
121		putchar(' ');
122		fprintPwd(stdout, entry, 0);
123	}
124	putchar('\n');
125	return GOT_ONE;
126}
127
128static int recursive_attrib(direntry_t *entry, MainParam_t *mp)
129{
130	mp->callback(entry, mp);
131	return mp->loop(mp->File, mp, "*");
132}
133
134
135static void usage(int ret) NORETURN;
136static void usage(int ret)
137{
138	fprintf(stderr, "Mtools version %s, dated %s\n",
139		mversion, mdate);
140	fprintf(stderr,
141		"Usage: %s [-p] [-a|+a] [-h|+h] [-r|+r] [-s|+s] msdosfile [msdosfiles...]\n",
142		progname);
143	exit(ret);
144}
145
146static int letterToCode(int letter)
147{
148	switch (toupper(letter)) {
149		case 'A':
150			return ATTR_ARCHIVE;
151		case 'H':
152			return ATTR_HIDDEN;
153		case 'R':
154			return ATTR_READONLY;
155		case 'S':
156			return ATTR_SYSTEM;
157		default:
158			usage(1);
159	}
160}
161
162
163void mattrib(int argc, char **argv, int type)
164{
165	Arg_t arg;
166	int view;
167	int c;
168	int concise;
169	int replay;
170	char *ptr;
171
172	arg.add = 0;
173	arg.remove = 0xff;
174	arg.recursive = 0;
175	arg.doPrintName = 1;
176	view = 0;
177	concise = 0;
178	replay = 0;
179
180	if(helpFlag(argc, argv))
181		usage(0);
182	while ((c = getopt(argc, argv, "i:/ahrsAHRSXph")) != EOF) {
183		switch (c) {
184			default:
185				arg.remove &= ~letterToCode(c);
186				break;
187			case 'i':
188				set_cmd_line_image(optarg, 0);
189				break;
190			case 'p':
191				replay = 1;
192				break;
193			case '/':
194				arg.recursive = 1;
195				break;
196			case 'X':
197				concise = 1;
198				break;
199			case 'h':
200				usage(0);
201			case '?':
202				usage(1);
203		}
204	}
205
206	for(;optind < argc;optind++) {
207		switch(argv[optind][0]) {
208			case '+':
209				for(ptr = argv[optind] + 1; *ptr; ptr++)
210					arg.add |= letterToCode(*ptr);
211				continue;
212			case '-':
213				for(ptr = argv[optind] + 1; *ptr; ptr++)
214					arg.remove &= ~letterToCode(*ptr);
215				continue;
216		}
217		break;
218	}
219
220	if(arg.remove == 0xff && !arg.add)
221		view = 1;
222
223	if (optind >= argc)
224		usage(1);
225
226	init_mp(&arg.mp);
227	if(view){
228		if(concise) {
229			arg.mp.callback = concise_view_attrib;
230			arg.doPrintName = (argc - optind > 1 ||
231					   arg.recursive ||
232					   strpbrk(argv[optind], "*[?") != 0);
233		} else if (replay) {
234			arg.mp.callback = replay_attrib;
235		} else
236			arg.mp.callback = view_attrib;
237		arg.mp.openflags = O_RDONLY;
238	} else {
239		arg.mp.callback = attrib_file;
240		arg.mp.openflags = O_RDWR;
241	}
242
243	if(arg.recursive)
244		arg.mp.dirCallback = recursive_attrib;
245
246	arg.mp.arg = (void *) &arg;
247	arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR;
248	if(arg.recursive)
249		arg.mp.lookupflags |= DO_OPEN_DIRS | NO_DOTS;
250	exit(main_loop(&arg.mp, argv + optind, argc - optind));
251}
252