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