Imported Upstream version 4.0.18
[platform/upstream/mtools.git] / mmd.c
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
39 typedef 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
50 typedef 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  */
61 static 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
107 static void usage(int ret) NORETURN;
108 static 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
120 Stream_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
140 static 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
156 void 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);
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 }