1*d5c9a868SElliott Hughes /* Copyright 1986-1992 Emmet P. Gray.
2*d5c9a868SElliott Hughes * Copyright 1996-2002,2007-2009 Alain Knaff.
3*d5c9a868SElliott Hughes * This file is part of mtools.
4*d5c9a868SElliott Hughes *
5*d5c9a868SElliott Hughes * Mtools is free software: you can redistribute it and/or modify
6*d5c9a868SElliott Hughes * it under the terms of the GNU General Public License as published by
7*d5c9a868SElliott Hughes * the Free Software Foundation, either version 3 of the License, or
8*d5c9a868SElliott Hughes * (at your option) any later version.
9*d5c9a868SElliott Hughes *
10*d5c9a868SElliott Hughes * Mtools is distributed in the hope that it will be useful,
11*d5c9a868SElliott Hughes * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*d5c9a868SElliott Hughes * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*d5c9a868SElliott Hughes * GNU General Public License for more details.
14*d5c9a868SElliott Hughes *
15*d5c9a868SElliott Hughes * You should have received a copy of the GNU General Public License
16*d5c9a868SElliott Hughes * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
17*d5c9a868SElliott Hughes *
18*d5c9a868SElliott Hughes * mmd.c
19*d5c9a868SElliott Hughes * Makes an MSDOS directory
20*d5c9a868SElliott Hughes */
21*d5c9a868SElliott Hughes
22*d5c9a868SElliott Hughes
23*d5c9a868SElliott Hughes #include "sysincludes.h"
24*d5c9a868SElliott Hughes #include "msdos.h"
25*d5c9a868SElliott Hughes #include "mtools.h"
26*d5c9a868SElliott Hughes #include "vfat.h"
27*d5c9a868SElliott Hughes #include "mainloop.h"
28*d5c9a868SElliott Hughes #include "plain_io.h"
29*d5c9a868SElliott Hughes #include "nameclash.h"
30*d5c9a868SElliott Hughes #include "file.h"
31*d5c9a868SElliott Hughes #include "fs.h"
32*d5c9a868SElliott Hughes
33*d5c9a868SElliott Hughes /*
34*d5c9a868SElliott Hughes * Preserve the file modification times after the fclose()
35*d5c9a868SElliott Hughes */
36*d5c9a868SElliott Hughes
37*d5c9a868SElliott Hughes typedef struct Arg_t {
38*d5c9a868SElliott Hughes char *target;
39*d5c9a868SElliott Hughes MainParam_t mp;
40*d5c9a868SElliott Hughes
41*d5c9a868SElliott Hughes Stream_t *SrcDir;
42*d5c9a868SElliott Hughes int entry;
43*d5c9a868SElliott Hughes ClashHandling_t ch;
44*d5c9a868SElliott Hughes Stream_t *targetDir;
45*d5c9a868SElliott Hughes } Arg_t;
46*d5c9a868SElliott Hughes
47*d5c9a868SElliott Hughes
48*d5c9a868SElliott Hughes typedef struct CreateArg_t {
49*d5c9a868SElliott Hughes Stream_t *Dir;
50*d5c9a868SElliott Hughes Stream_t *NewDir;
51*d5c9a868SElliott Hughes unsigned char attr;
52*d5c9a868SElliott Hughes time_t mtime;
53*d5c9a868SElliott Hughes } CreateArg_t;
54*d5c9a868SElliott Hughes
55*d5c9a868SElliott Hughes /*
56*d5c9a868SElliott Hughes * Open the named file for read, create the cluster chain, return the
57*d5c9a868SElliott Hughes * directory structure or NULL on error.
58*d5c9a868SElliott Hughes */
makeit(dos_name_t * dosname,char * longname UNUSEDP,void * arg0,direntry_t * targetEntry)59*d5c9a868SElliott Hughes static int makeit(dos_name_t *dosname,
60*d5c9a868SElliott Hughes char *longname UNUSEDP,
61*d5c9a868SElliott Hughes void *arg0,
62*d5c9a868SElliott Hughes direntry_t *targetEntry)
63*d5c9a868SElliott Hughes {
64*d5c9a868SElliott Hughes Stream_t *Target;
65*d5c9a868SElliott Hughes CreateArg_t *arg = (CreateArg_t *) arg0;
66*d5c9a868SElliott Hughes uint32_t fat;
67*d5c9a868SElliott Hughes direntry_t subEntry;
68*d5c9a868SElliott Hughes
69*d5c9a868SElliott Hughes /* will it fit? At least one cluster must be free */
70*d5c9a868SElliott Hughes if (!getfreeMinClusters(targetEntry->Dir, 1))
71*d5c9a868SElliott Hughes return -1;
72*d5c9a868SElliott Hughes
73*d5c9a868SElliott Hughes mk_entry(dosname, ATTR_DIR, 1, 0, arg->mtime, &targetEntry->dir);
74*d5c9a868SElliott Hughes Target = OpenFileByDirentry(targetEntry);
75*d5c9a868SElliott Hughes if(!Target){
76*d5c9a868SElliott Hughes fprintf(stderr,"Could not open Target\n");
77*d5c9a868SElliott Hughes return -1;
78*d5c9a868SElliott Hughes }
79*d5c9a868SElliott Hughes
80*d5c9a868SElliott Hughes /* this allocates the first cluster for our directory */
81*d5c9a868SElliott Hughes
82*d5c9a868SElliott Hughes initializeDirentry(&subEntry, Target);
83*d5c9a868SElliott Hughes
84*d5c9a868SElliott Hughes subEntry.entry = 1;
85*d5c9a868SElliott Hughes GET_DATA(targetEntry->Dir, 0, 0, 0, &fat);
86*d5c9a868SElliott Hughes if (fat == fat32RootCluster(targetEntry->Dir)) {
87*d5c9a868SElliott Hughes fat = 0;
88*d5c9a868SElliott Hughes }
89*d5c9a868SElliott Hughes mk_entry_from_base(".. ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir);
90*d5c9a868SElliott Hughes dir_write(&subEntry);
91*d5c9a868SElliott Hughes
92*d5c9a868SElliott Hughes FLUSH(Target);
93*d5c9a868SElliott Hughes subEntry.entry = 0;
94*d5c9a868SElliott Hughes GET_DATA(Target, 0, 0, 0, &fat);
95*d5c9a868SElliott Hughes mk_entry_from_base(". ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir);
96*d5c9a868SElliott Hughes dir_write(&subEntry);
97*d5c9a868SElliott Hughes
98*d5c9a868SElliott Hughes mk_entry(dosname, ATTR_DIR | arg->attr, fat, 0, arg->mtime,
99*d5c9a868SElliott Hughes &targetEntry->dir);
100*d5c9a868SElliott Hughes arg->NewDir = Target;
101*d5c9a868SElliott Hughes return 0;
102*d5c9a868SElliott Hughes }
103*d5c9a868SElliott Hughes
104*d5c9a868SElliott Hughes
105*d5c9a868SElliott Hughes static void usage(int ret) NORETURN;
usage(int ret)106*d5c9a868SElliott Hughes static void usage(int ret)
107*d5c9a868SElliott Hughes {
108*d5c9a868SElliott Hughes fprintf(stderr,
109*d5c9a868SElliott Hughes "Mtools version %s, dated %s\n", mversion, mdate);
110*d5c9a868SElliott Hughes fprintf(stderr,
111*d5c9a868SElliott Hughes "Usage: %s [-D clash_option] file targetfile\n", progname);
112*d5c9a868SElliott Hughes fprintf(stderr,
113*d5c9a868SElliott Hughes " %s [-D clash_option] file [files...] target_directory\n",
114*d5c9a868SElliott Hughes progname);
115*d5c9a868SElliott Hughes exit(ret);
116*d5c9a868SElliott Hughes }
117*d5c9a868SElliott Hughes
createDir(Stream_t * Dir,const char * filename,ClashHandling_t * ch,unsigned char attr,time_t mtime)118*d5c9a868SElliott Hughes Stream_t *createDir(Stream_t *Dir, const char *filename, ClashHandling_t *ch,
119*d5c9a868SElliott Hughes unsigned char attr, time_t mtime)
120*d5c9a868SElliott Hughes {
121*d5c9a868SElliott Hughes CreateArg_t arg;
122*d5c9a868SElliott Hughes int ret;
123*d5c9a868SElliott Hughes
124*d5c9a868SElliott Hughes arg.Dir = Dir;
125*d5c9a868SElliott Hughes arg.attr = attr;
126*d5c9a868SElliott Hughes arg.mtime = mtime;
127*d5c9a868SElliott Hughes
128*d5c9a868SElliott Hughes if (!getfreeMinClusters(Dir, 1))
129*d5c9a868SElliott Hughes return NULL;
130*d5c9a868SElliott Hughes
131*d5c9a868SElliott Hughes ret = mwrite_one(Dir, filename, 0, makeit, &arg, ch);
132*d5c9a868SElliott Hughes if(ret < 1)
133*d5c9a868SElliott Hughes return NULL;
134*d5c9a868SElliott Hughes else
135*d5c9a868SElliott Hughes return arg.NewDir;
136*d5c9a868SElliott Hughes }
137*d5c9a868SElliott Hughes
createDirCallback(direntry_t * entry UNUSEDP,MainParam_t * mp)138*d5c9a868SElliott Hughes static int createDirCallback(direntry_t *entry UNUSEDP, MainParam_t *mp)
139*d5c9a868SElliott Hughes {
140*d5c9a868SElliott Hughes Stream_t *ret;
141*d5c9a868SElliott Hughes time_t now;
142*d5c9a868SElliott Hughes
143*d5c9a868SElliott Hughes ret = createDir(mp->File, mp->targetName, &((Arg_t *)(mp->arg))->ch,
144*d5c9a868SElliott Hughes ATTR_DIR, getTimeNow(&now));
145*d5c9a868SElliott Hughes if(ret == NULL)
146*d5c9a868SElliott Hughes return ERROR_ONE;
147*d5c9a868SElliott Hughes else {
148*d5c9a868SElliott Hughes FREE(&ret);
149*d5c9a868SElliott Hughes return GOT_ONE;
150*d5c9a868SElliott Hughes }
151*d5c9a868SElliott Hughes
152*d5c9a868SElliott Hughes }
153*d5c9a868SElliott Hughes
154*d5c9a868SElliott Hughes void mmd(int argc, char **argv, int type UNUSEDP) NORETURN;
mmd(int argc,char ** argv,int type UNUSEDP)155*d5c9a868SElliott Hughes void mmd(int argc, char **argv, int type UNUSEDP)
156*d5c9a868SElliott Hughes {
157*d5c9a868SElliott Hughes Arg_t arg;
158*d5c9a868SElliott Hughes int c;
159*d5c9a868SElliott Hughes
160*d5c9a868SElliott Hughes /* get command line options */
161*d5c9a868SElliott Hughes
162*d5c9a868SElliott Hughes init_clash_handling(& arg.ch);
163*d5c9a868SElliott Hughes
164*d5c9a868SElliott Hughes /* get command line options */
165*d5c9a868SElliott Hughes if(helpFlag(argc, argv))
166*d5c9a868SElliott Hughes usage(0);
167*d5c9a868SElliott Hughes while ((c = getopt(argc, argv, "i:D:oh")) != EOF) {
168*d5c9a868SElliott Hughes switch (c) {
169*d5c9a868SElliott Hughes case 'i':
170*d5c9a868SElliott Hughes set_cmd_line_image(optarg);
171*d5c9a868SElliott Hughes break;
172*d5c9a868SElliott Hughes case '?':
173*d5c9a868SElliott Hughes usage(1);
174*d5c9a868SElliott Hughes case 'o':
175*d5c9a868SElliott Hughes handle_clash_options(&arg.ch, (char) c);
176*d5c9a868SElliott Hughes break;
177*d5c9a868SElliott Hughes case 'D':
178*d5c9a868SElliott Hughes if(handle_clash_options(&arg.ch, *optarg))
179*d5c9a868SElliott Hughes usage(1);
180*d5c9a868SElliott Hughes break;
181*d5c9a868SElliott Hughes case 'h':
182*d5c9a868SElliott Hughes usage(0);
183*d5c9a868SElliott Hughes default:
184*d5c9a868SElliott Hughes usage(1);
185*d5c9a868SElliott Hughes }
186*d5c9a868SElliott Hughes }
187*d5c9a868SElliott Hughes
188*d5c9a868SElliott Hughes if (argc - optind < 1)
189*d5c9a868SElliott Hughes usage(1);
190*d5c9a868SElliott Hughes
191*d5c9a868SElliott Hughes init_mp(&arg.mp);
192*d5c9a868SElliott Hughes arg.mp.arg = (void *) &arg;
193*d5c9a868SElliott Hughes arg.mp.openflags = O_RDWR;
194*d5c9a868SElliott Hughes arg.mp.callback = createDirCallback;
195*d5c9a868SElliott Hughes arg.mp.lookupflags = OPEN_PARENT | DO_OPEN_DIRS;
196*d5c9a868SElliott Hughes exit(main_loop(&arg.mp, argv + optind, argc - optind));
197*d5c9a868SElliott Hughes }
198