xref: /aosp_15_r20/external/mtools/mmove.c (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
1*d5c9a868SElliott Hughes /*  Copyright 1996-1998,2000-2002,2005,2007-2009 Alain Knaff.
2*d5c9a868SElliott Hughes  *  This file is part of mtools.
3*d5c9a868SElliott Hughes  *
4*d5c9a868SElliott Hughes  *  Mtools is free software: you can redistribute it and/or modify
5*d5c9a868SElliott Hughes  *  it under the terms of the GNU General Public License as published by
6*d5c9a868SElliott Hughes  *  the Free Software Foundation, either version 3 of the License, or
7*d5c9a868SElliott Hughes  *  (at your option) any later version.
8*d5c9a868SElliott Hughes  *
9*d5c9a868SElliott Hughes  *  Mtools is distributed in the hope that it will be useful,
10*d5c9a868SElliott Hughes  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11*d5c9a868SElliott Hughes  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*d5c9a868SElliott Hughes  *  GNU General Public License for more details.
13*d5c9a868SElliott Hughes  *
14*d5c9a868SElliott Hughes  *  You should have received a copy of the GNU General Public License
15*d5c9a868SElliott Hughes  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16*d5c9a868SElliott Hughes  *
17*d5c9a868SElliott Hughes  * mmove.c
18*d5c9a868SElliott Hughes  * Renames/moves an MSDOS file
19*d5c9a868SElliott Hughes  *
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 	const char *fromname;
39*d5c9a868SElliott Hughes 	int verbose;
40*d5c9a868SElliott Hughes 	MainParam_t mp;
41*d5c9a868SElliott Hughes 
42*d5c9a868SElliott Hughes 	direntry_t *entry;
43*d5c9a868SElliott Hughes 	ClashHandling_t ch;
44*d5c9a868SElliott Hughes } Arg_t;
45*d5c9a868SElliott Hughes 
46*d5c9a868SElliott Hughes 
47*d5c9a868SElliott Hughes /*
48*d5c9a868SElliott Hughes  * Open the named file for read, create the cluster chain, return the
49*d5c9a868SElliott Hughes  * directory structure or NULL on error.
50*d5c9a868SElliott Hughes  */
renameit(dos_name_t * dosname,char * longname UNUSEDP,void * arg0,direntry_t * targetEntry)51*d5c9a868SElliott Hughes static int renameit(dos_name_t *dosname,
52*d5c9a868SElliott Hughes 		    char *longname UNUSEDP,
53*d5c9a868SElliott Hughes 		    void *arg0,
54*d5c9a868SElliott Hughes 		    direntry_t *targetEntry)
55*d5c9a868SElliott Hughes {
56*d5c9a868SElliott Hughes 	Arg_t *arg = (Arg_t *) arg0;
57*d5c9a868SElliott Hughes 	uint32_t fat;
58*d5c9a868SElliott Hughes 
59*d5c9a868SElliott Hughes 	targetEntry->dir = arg->entry->dir;
60*d5c9a868SElliott Hughes 	dosnameToDirentry(dosname, &targetEntry->dir);
61*d5c9a868SElliott Hughes 
62*d5c9a868SElliott Hughes 	if(IS_DIR(targetEntry)) {
63*d5c9a868SElliott Hughes 		direntry_t *movedEntry;
64*d5c9a868SElliott Hughes 
65*d5c9a868SElliott Hughes 		/* get old direntry. It is important that we do this
66*d5c9a868SElliott Hughes 		 * on the actual direntry which is stored in the file,
67*d5c9a868SElliott Hughes 		 * and not on a copy, because we will modify it, and the
68*d5c9a868SElliott Hughes 		 * modification should be visible at file
69*d5c9a868SElliott Hughes 		 * de-allocation time */
70*d5c9a868SElliott Hughes 		movedEntry = getDirentry(arg->mp.File);
71*d5c9a868SElliott Hughes 		if(movedEntry->Dir != targetEntry->Dir) {
72*d5c9a868SElliott Hughes 			/* we are indeed moving it to a new directory */
73*d5c9a868SElliott Hughes 			direntry_t subEntry;
74*d5c9a868SElliott Hughes 			Stream_t *oldDir;
75*d5c9a868SElliott Hughes 			/* we have a directory here. Change its parent link */
76*d5c9a868SElliott Hughes 
77*d5c9a868SElliott Hughes 			initializeDirentry(&subEntry, arg->mp.File);
78*d5c9a868SElliott Hughes 
79*d5c9a868SElliott Hughes 			switch(vfat_lookup(&subEntry, "..", 2, ACCEPT_DIR,
80*d5c9a868SElliott Hughes 					   NULL, 0, NULL, 0)) {
81*d5c9a868SElliott Hughes 			    case -1:
82*d5c9a868SElliott Hughes 				fprintf(stderr,
83*d5c9a868SElliott Hughes 					" Directory has no parent entry\n");
84*d5c9a868SElliott Hughes 				break;
85*d5c9a868SElliott Hughes 			    case -2:
86*d5c9a868SElliott Hughes 				return ERROR_ONE;
87*d5c9a868SElliott Hughes 			    case 0:
88*d5c9a868SElliott Hughes 				GET_DATA(targetEntry->Dir, 0, 0, 0, &fat);
89*d5c9a868SElliott Hughes 				if (fat == fat32RootCluster(targetEntry->Dir)) {
90*d5c9a868SElliott Hughes 				    fat = 0;
91*d5c9a868SElliott Hughes 				}
92*d5c9a868SElliott Hughes 
93*d5c9a868SElliott Hughes 				subEntry.dir.start[1] = (fat >> 8) & 0xff;
94*d5c9a868SElliott Hughes 				subEntry.dir.start[0] = fat & 0xff;
95*d5c9a868SElliott Hughes 				dir_write(&subEntry);
96*d5c9a868SElliott Hughes 				if(arg->verbose){
97*d5c9a868SElliott Hughes 					fprintf(stderr,
98*d5c9a868SElliott Hughes 						"Easy, isn't it? I wonder why DOS can't do this.\n");
99*d5c9a868SElliott Hughes 				}
100*d5c9a868SElliott Hughes 				break;
101*d5c9a868SElliott Hughes 			}
102*d5c9a868SElliott Hughes 
103*d5c9a868SElliott Hughes 			wipeEntry(movedEntry);
104*d5c9a868SElliott Hughes 
105*d5c9a868SElliott Hughes 			/* free the old parent, allocate the new one. */
106*d5c9a868SElliott Hughes 			oldDir = movedEntry->Dir;
107*d5c9a868SElliott Hughes 			*movedEntry = *targetEntry;
108*d5c9a868SElliott Hughes 			COPY(targetEntry->Dir);
109*d5c9a868SElliott Hughes 			FREE(&oldDir);
110*d5c9a868SElliott Hughes 			return 0;
111*d5c9a868SElliott Hughes 		}
112*d5c9a868SElliott Hughes 	}
113*d5c9a868SElliott Hughes 
114*d5c9a868SElliott Hughes 	/* wipe out original entry */
115*d5c9a868SElliott Hughes 	wipeEntry(arg->mp.direntry);
116*d5c9a868SElliott Hughes 	return 0;
117*d5c9a868SElliott Hughes }
118*d5c9a868SElliott Hughes 
119*d5c9a868SElliott Hughes 
120*d5c9a868SElliott Hughes 
rename_file(direntry_t * entry,MainParam_t * mp)121*d5c9a868SElliott Hughes static int rename_file(direntry_t *entry, MainParam_t *mp)
122*d5c9a868SElliott Hughes /* rename a messy DOS file to another messy DOS file */
123*d5c9a868SElliott Hughes {
124*d5c9a868SElliott Hughes 	int result;
125*d5c9a868SElliott Hughes 	Stream_t *targetDir;
126*d5c9a868SElliott Hughes 	char *shortname;
127*d5c9a868SElliott Hughes 	const char *longname;
128*d5c9a868SElliott Hughes 
129*d5c9a868SElliott Hughes 	Arg_t * arg = (Arg_t *) (mp->arg);
130*d5c9a868SElliott Hughes 
131*d5c9a868SElliott Hughes 	arg->entry = entry;
132*d5c9a868SElliott Hughes 	targetDir = mp->targetDir;
133*d5c9a868SElliott Hughes 
134*d5c9a868SElliott Hughes 	if (targetDir == entry->Dir){
135*d5c9a868SElliott Hughes 		arg->ch.ignore_entry = -1;
136*d5c9a868SElliott Hughes 		arg->ch.source = entry->entry;
137*d5c9a868SElliott Hughes 		arg->ch.source_entry = entry->entry;
138*d5c9a868SElliott Hughes 	} else {
139*d5c9a868SElliott Hughes 		arg->ch.ignore_entry = -1;
140*d5c9a868SElliott Hughes 		arg->ch.source = -2;
141*d5c9a868SElliott Hughes 	}
142*d5c9a868SElliott Hughes 
143*d5c9a868SElliott Hughes 	longname = mpPickTargetName(mp);
144*d5c9a868SElliott Hughes 	shortname = 0;
145*d5c9a868SElliott Hughes 	result = mwrite_one(targetDir, longname, shortname,
146*d5c9a868SElliott Hughes 			    renameit, (void *)arg, &arg->ch);
147*d5c9a868SElliott Hughes 	if(result == 1)
148*d5c9a868SElliott Hughes 		return GOT_ONE;
149*d5c9a868SElliott Hughes 	else
150*d5c9a868SElliott Hughes 		return ERROR_ONE;
151*d5c9a868SElliott Hughes }
152*d5c9a868SElliott Hughes 
153*d5c9a868SElliott Hughes 
rename_directory(direntry_t * entry,MainParam_t * mp)154*d5c9a868SElliott Hughes static int rename_directory(direntry_t *entry, MainParam_t *mp)
155*d5c9a868SElliott Hughes {
156*d5c9a868SElliott Hughes 	int ret;
157*d5c9a868SElliott Hughes 
158*d5c9a868SElliott Hughes 	/* moves a DOS dir */
159*d5c9a868SElliott Hughes 	if(isSubdirOf(mp->targetDir, mp->File)) {
160*d5c9a868SElliott Hughes 		fprintf(stderr, "Cannot move directory ");
161*d5c9a868SElliott Hughes 		fprintPwd(stderr, entry,0);
162*d5c9a868SElliott Hughes 		fprintf(stderr, " into one of its own subdirectories (");
163*d5c9a868SElliott Hughes 		fprintPwd(stderr, getDirentry(mp->targetDir),0);
164*d5c9a868SElliott Hughes 		fprintf(stderr, ")\n");
165*d5c9a868SElliott Hughes 		return ERROR_ONE;
166*d5c9a868SElliott Hughes 	}
167*d5c9a868SElliott Hughes 
168*d5c9a868SElliott Hughes 	if(entry->entry == -3) {
169*d5c9a868SElliott Hughes 		fprintf(stderr, "Cannot move a root directory: ");
170*d5c9a868SElliott Hughes 		fprintPwd(stderr, entry,0);
171*d5c9a868SElliott Hughes 		return ERROR_ONE;
172*d5c9a868SElliott Hughes 	}
173*d5c9a868SElliott Hughes 
174*d5c9a868SElliott Hughes 	ret = rename_file(entry, mp);
175*d5c9a868SElliott Hughes 	if(ret & ERROR_ONE)
176*d5c9a868SElliott Hughes 		return ret;
177*d5c9a868SElliott Hughes 
178*d5c9a868SElliott Hughes 	return ret;
179*d5c9a868SElliott Hughes }
180*d5c9a868SElliott Hughes 
rename_oldsyntax(direntry_t * entry,MainParam_t * mp)181*d5c9a868SElliott Hughes static int rename_oldsyntax(direntry_t *entry, MainParam_t *mp)
182*d5c9a868SElliott Hughes {
183*d5c9a868SElliott Hughes 	int result;
184*d5c9a868SElliott Hughes 	Stream_t *targetDir;
185*d5c9a868SElliott Hughes 	const char *shortname, *longname;
186*d5c9a868SElliott Hughes 
187*d5c9a868SElliott Hughes 	Arg_t * arg = (Arg_t *) (mp->arg);
188*d5c9a868SElliott Hughes 	arg->entry = entry;
189*d5c9a868SElliott Hughes 	targetDir = entry->Dir;
190*d5c9a868SElliott Hughes 
191*d5c9a868SElliott Hughes 	arg->ch.ignore_entry = -1;
192*d5c9a868SElliott Hughes 	arg->ch.source = entry->entry;
193*d5c9a868SElliott Hughes 	arg->ch.source_entry = entry->entry;
194*d5c9a868SElliott Hughes 
195*d5c9a868SElliott Hughes #if 0
196*d5c9a868SElliott Hughes 	if(!strcasecmp(mp->shortname, arg->fromname)){
197*d5c9a868SElliott Hughes 		longname = mp->longname;
198*d5c9a868SElliott Hughes 		shortname = mp->targetName;
199*d5c9a868SElliott Hughes 	} else {
200*d5c9a868SElliott Hughes #endif
201*d5c9a868SElliott Hughes 		longname = mp->targetName;
202*d5c9a868SElliott Hughes 		shortname = 0;
203*d5c9a868SElliott Hughes #if 0
204*d5c9a868SElliott Hughes 	}
205*d5c9a868SElliott Hughes #endif
206*d5c9a868SElliott Hughes 	result = mwrite_one(targetDir, longname, shortname,
207*d5c9a868SElliott Hughes 			    renameit, (void *)arg, &arg->ch);
208*d5c9a868SElliott Hughes 	if(result == 1)
209*d5c9a868SElliott Hughes 		return GOT_ONE;
210*d5c9a868SElliott Hughes 	else
211*d5c9a868SElliott Hughes 		return ERROR_ONE;
212*d5c9a868SElliott Hughes }
213*d5c9a868SElliott Hughes 
214*d5c9a868SElliott Hughes 
215*d5c9a868SElliott Hughes static void usage(int ret) NORETURN;
usage(int ret)216*d5c9a868SElliott Hughes static void usage(int ret)
217*d5c9a868SElliott Hughes {
218*d5c9a868SElliott Hughes 	fprintf(stderr,
219*d5c9a868SElliott Hughes 		"Mtools version %s, dated %s\n", mversion, mdate);
220*d5c9a868SElliott Hughes 	fprintf(stderr,
221*d5c9a868SElliott Hughes 		"Usage: %s [-vV] [-D clash_option] file targetfile\n", progname);
222*d5c9a868SElliott Hughes 	fprintf(stderr,
223*d5c9a868SElliott Hughes 		"       %s [-vV] [-D clash_option] file [files...] target_directory\n",
224*d5c9a868SElliott Hughes 		progname);
225*d5c9a868SElliott Hughes 	exit(ret);
226*d5c9a868SElliott Hughes }
227*d5c9a868SElliott Hughes 
228*d5c9a868SElliott Hughes void mmove(int argc, char **argv, int oldsyntax) NORETURN;
mmove(int argc,char ** argv,int oldsyntax)229*d5c9a868SElliott Hughes void mmove(int argc, char **argv, int oldsyntax)
230*d5c9a868SElliott Hughes {
231*d5c9a868SElliott Hughes 	Arg_t arg;
232*d5c9a868SElliott Hughes 	int c;
233*d5c9a868SElliott Hughes 	char shortname[12*4+1];
234*d5c9a868SElliott Hughes 	char longname[4*MAX_VNAMELEN+1];
235*d5c9a868SElliott Hughes 	char def_drive;
236*d5c9a868SElliott Hughes 	int i;
237*d5c9a868SElliott Hughes 
238*d5c9a868SElliott Hughes 	/* get command line options */
239*d5c9a868SElliott Hughes 
240*d5c9a868SElliott Hughes 	init_clash_handling(& arg.ch);
241*d5c9a868SElliott Hughes 
242*d5c9a868SElliott Hughes 	/* get command line options */
243*d5c9a868SElliott Hughes 	arg.verbose = 0;
244*d5c9a868SElliott Hughes 	if(helpFlag(argc, argv))
245*d5c9a868SElliott Hughes 		usage(0);
246*d5c9a868SElliott Hughes 	while ((c = getopt(argc, argv, "i:vD:oh")) != EOF) {
247*d5c9a868SElliott Hughes 		switch (c) {
248*d5c9a868SElliott Hughes 			case 'i':
249*d5c9a868SElliott Hughes 				set_cmd_line_image(optarg);
250*d5c9a868SElliott Hughes 				break;
251*d5c9a868SElliott Hughes 			case 'v':	/* dummy option for mcopy */
252*d5c9a868SElliott Hughes 				arg.verbose = 1;
253*d5c9a868SElliott Hughes 				break;
254*d5c9a868SElliott Hughes 			case 'o':
255*d5c9a868SElliott Hughes 				handle_clash_options(&arg.ch, (char)c);
256*d5c9a868SElliott Hughes 				break;
257*d5c9a868SElliott Hughes 			case 'D':
258*d5c9a868SElliott Hughes 				if(handle_clash_options(&arg.ch, *optarg))
259*d5c9a868SElliott Hughes 					usage(1);
260*d5c9a868SElliott Hughes 				break;
261*d5c9a868SElliott Hughes 			case 'h':
262*d5c9a868SElliott Hughes 				usage(0);
263*d5c9a868SElliott Hughes 			case '?':
264*d5c9a868SElliott Hughes 				usage(1);
265*d5c9a868SElliott Hughes 			default:
266*d5c9a868SElliott Hughes 				break;
267*d5c9a868SElliott Hughes 		}
268*d5c9a868SElliott Hughes 	}
269*d5c9a868SElliott Hughes 
270*d5c9a868SElliott Hughes 	if (argc - optind < 2)
271*d5c9a868SElliott Hughes 		usage(1);
272*d5c9a868SElliott Hughes 
273*d5c9a868SElliott Hughes 	init_mp(&arg.mp);
274*d5c9a868SElliott Hughes 	arg.mp.arg = (void *) &arg;
275*d5c9a868SElliott Hughes 	arg.mp.openflags = O_RDWR;
276*d5c9a868SElliott Hughes 
277*d5c9a868SElliott Hughes 	/* look for a default drive */
278*d5c9a868SElliott Hughes 	def_drive = '\0';
279*d5c9a868SElliott Hughes 	for(i=optind; i<argc; i++)
280*d5c9a868SElliott Hughes 		if(argv[i][0] && argv[i][1] == ':' ){
281*d5c9a868SElliott Hughes 			if(!def_drive)
282*d5c9a868SElliott Hughes 				def_drive = ch_toupper(argv[i][0]);
283*d5c9a868SElliott Hughes 			else if(def_drive != ch_toupper(argv[i][0])){
284*d5c9a868SElliott Hughes 				fprintf(stderr,
285*d5c9a868SElliott Hughes 					"Cannot move files across different drives\n");
286*d5c9a868SElliott Hughes 				exit(1);
287*d5c9a868SElliott Hughes 			}
288*d5c9a868SElliott Hughes 		}
289*d5c9a868SElliott Hughes 
290*d5c9a868SElliott Hughes 	if(def_drive)
291*d5c9a868SElliott Hughes 		*(arg.mp.mcwd) = def_drive;
292*d5c9a868SElliott Hughes 
293*d5c9a868SElliott Hughes 	if (oldsyntax && (argc - optind != 2 || strpbrk(":/", argv[argc-1])))
294*d5c9a868SElliott Hughes 		oldsyntax = 0;
295*d5c9a868SElliott Hughes 
296*d5c9a868SElliott Hughes 	arg.mp.lookupflags =
297*d5c9a868SElliott Hughes 	  ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS | NO_UNIX;
298*d5c9a868SElliott Hughes 
299*d5c9a868SElliott Hughes 	if (!oldsyntax){
300*d5c9a868SElliott Hughes 		target_lookup(&arg.mp, argv[argc-1]);
301*d5c9a868SElliott Hughes 		arg.mp.callback = rename_file;
302*d5c9a868SElliott Hughes 		arg.mp.dirCallback = rename_directory;
303*d5c9a868SElliott Hughes 	} else {
304*d5c9a868SElliott Hughes 		/* do not look up the target; it will be the same dir as the
305*d5c9a868SElliott Hughes 		 * source */
306*d5c9a868SElliott Hughes 		arg.fromname = argv[optind];
307*d5c9a868SElliott Hughes 		if(arg.fromname[0] && arg.fromname[1] == ':')
308*d5c9a868SElliott Hughes 			arg.fromname += 2;
309*d5c9a868SElliott Hughes 		arg.fromname = _basename(arg.fromname);
310*d5c9a868SElliott Hughes 		arg.mp.targetName = strdup(argv[argc-1]);
311*d5c9a868SElliott Hughes 		arg.mp.callback = rename_oldsyntax;
312*d5c9a868SElliott Hughes 	}
313*d5c9a868SElliott Hughes 
314*d5c9a868SElliott Hughes 
315*d5c9a868SElliott Hughes 	arg.mp.longname.data = longname;
316*d5c9a868SElliott Hughes 	arg.mp.longname.len = sizeof(longname);
317*d5c9a868SElliott Hughes 	longname[0]='\0';
318*d5c9a868SElliott Hughes 
319*d5c9a868SElliott Hughes 	arg.mp.shortname.data = shortname;
320*d5c9a868SElliott Hughes 	arg.mp.shortname.len = sizeof(shortname);
321*d5c9a868SElliott Hughes 	shortname[0]='\0';
322*d5c9a868SElliott Hughes 
323*d5c9a868SElliott Hughes 	exit(main_loop(&arg.mp, argv + optind, argc - optind - 1));
324*d5c9a868SElliott Hughes }
325