1/*  Copyright 1986-1992 Emmet P. Gray.
2 *  Copyright 1996-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 * mmd.c
19 * Makes an MSDOS directory
20 */
21
22
23#define LOWERCASE
24
25#include "sysincludes.h"
26#include "msdos.h"
27#include "mtools.h"
28#include "vfat.h"
29#include "mainloop.h"
30#include "plain_io.h"
31#include "nameclash.h"
32#include "file.h"
33#include "fs.h"
34
35/*
36 * Preserve the file modification times after the fclose()
37 */
38
39typedef struct Arg_t {
40	char *target;
41	MainParam_t mp;
42
43	Stream_t *SrcDir;
44	int entry;
45	ClashHandling_t ch;
46	Stream_t *targetDir;
47} Arg_t;
48
49
50typedef struct CreateArg_t {
51	Stream_t *Dir;
52	Stream_t *NewDir;
53	unsigned char attr;
54	time_t mtime;
55} CreateArg_t;
56
57/*
58 * Open the named file for read, create the cluster chain, return the
59 * directory structure or NULL on error.
60 */
61static int makeit(dos_name_t *dosname,
62		  char *longname,
63		  void *arg0,
64		  direntry_t *targetEntry)
65{
66	Stream_t *Target;
67	CreateArg_t *arg = (CreateArg_t *) arg0;
68	int fat;
69	direntry_t subEntry;
70
71	/* will it fit? At least one cluster must be free */
72	if (!getfreeMinClusters(targetEntry->Dir, 1))
73		return -1;
74
75	mk_entry(dosname, ATTR_DIR, 1, 0, arg->mtime, &targetEntry->dir);
76	Target = OpenFileByDirentry(targetEntry);
77	if(!Target){
78		fprintf(stderr,"Could not open Target\n");
79		return -1;
80	}
81
82	/* this allocates the first cluster for our directory */
83
84	initializeDirentry(&subEntry, Target);
85
86	subEntry.entry = 1;
87	GET_DATA(targetEntry->Dir, 0, 0, 0, &fat);
88	if (fat == fat32RootCluster(targetEntry->Dir)) {
89	    fat = 0;
90	}
91	mk_entry_from_base("..      ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir);
92	dir_write(&subEntry);
93
94	FLUSH((Stream_t *) Target);
95	subEntry.entry = 0;
96	GET_DATA(Target, 0, 0, 0, &fat);
97	mk_entry_from_base(".       ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir);
98	dir_write(&subEntry);
99
100	mk_entry(dosname, ATTR_DIR | arg->attr, fat, 0, arg->mtime,
101		 &targetEntry->dir);
102	arg->NewDir = Target;
103	return 0;
104}
105
106
107static void usage(int ret) NORETURN;
108static void usage(int ret)
109{
110	fprintf(stderr,
111		"Mtools version %s, dated %s\n", mversion, mdate);
112	fprintf(stderr,
113		"Usage: %s [-D clash_option] file targetfile\n", progname);
114	fprintf(stderr,
115		"       %s [-D clash_option] file [files...] target_directory\n",
116		progname);
117	exit(ret);
118}
119
120Stream_t *createDir(Stream_t *Dir, const char *filename, ClashHandling_t *ch,
121					unsigned char attr, time_t mtime)
122{
123	CreateArg_t arg;
124	int ret;
125
126	arg.Dir = Dir;
127	arg.attr = attr;
128	arg.mtime = mtime;
129
130	if (!getfreeMinClusters(Dir, 1))
131		return NULL;
132
133	ret = mwrite_one(Dir, filename, 0, makeit, &arg, ch);
134	if(ret < 1)
135		return NULL;
136	else
137		return arg.NewDir;
138}
139
140static int createDirCallback(direntry_t *entry, MainParam_t *mp)
141{
142	Stream_t *ret;
143	time_t now;
144
145	ret = createDir(mp->File, mp->targetName, &((Arg_t *)(mp->arg))->ch,
146					ATTR_DIR, getTimeNow(&now));
147	if(ret == NULL)
148		return ERROR_ONE;
149	else {
150		FREE(&ret);
151		return GOT_ONE;
152	}
153
154}
155
156void mmd(int argc, char **argv, int type)
157{
158	Arg_t arg;
159	int c;
160
161	/* get command line options */
162
163	init_clash_handling(& arg.ch);
164
165	/* get command line options */
166	if(helpFlag(argc, argv))
167		usage(0);
168	while ((c = getopt(argc, argv, "i:D:oh")) != EOF) {
169		switch (c) {
170			case 'i':
171				set_cmd_line_image(optarg, 0);
172				break;
173			case '?':
174				usage(1);
175			case 'o':
176				handle_clash_options(&arg.ch, c);
177				break;
178			case 'D':
179				if(handle_clash_options(&arg.ch, *optarg))
180					usage(1);
181				break;
182			case 'h':
183				usage(0);
184			default:
185				usage(1);
186				break;
187		}
188	}
189
190	if (argc - optind < 1)
191		usage(1);
192
193	init_mp(&arg.mp);
194	arg.mp.arg = (void *) &arg;
195	arg.mp.openflags = O_RDWR;
196	arg.mp.callback = createDirCallback;
197	arg.mp.lookupflags = OPEN_PARENT | DO_OPEN_DIRS;
198	exit(main_loop(&arg.mp, argv + optind, argc - optind));
199}
200