1 /* $Header: /home/ksheff/src/e2tools/RCS/mv.c,v 0.1 2002/03/21 09:03:25 ksheff Exp $ */
2 /*
3 * mv.c
4 *
5 * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
6 * under the terms of the GNU Public License.
7 *
8 */
9
10 /* Description */
11 /*
12 * Module to move/rename files
13 *
14 */
15 /*
16 * $Log: mv.c,v $
17 * Revision 0.1 2002/03/21 09:03:25 ksheff
18 * initial revision.
19 *
20 */
21
22 /* Feature Test Switches */
23 /* Headers */
24 #include "e2tools.h"
25
26 /* Macros */
27 #define USAGE "Usage: e2mv [-vfs] source1 [... sourceN] destination\n"
28
29 /* Local Prototypes */
30 static long
31 do_swap(int force, int verbose, int curidx, int argc, char **argv);
32
33 /* Name: main_e2mv()
34 *
35 * Description:
36 *
37 * This function reads the command line arguments and moves or renames files
38 * in an ext2fs file system
39 *
40 * Algorithm:
41 *
42 * Read any command line switches
43 * Get the first source file specification
44 * If we are performing a file swap, call do_swap()
45 * Open the file system
46 * Get the destination and determine if it is a directory
47 * If not, then get the destination's directory and basename
48 * Also check that the number of source files are no more than one
49 * For each source file
50 * Get the directory and basename of the source file
51 * Determine the inode number for the source file
52 * Create the link
53 * Unlink the original source file.
54 *
55 * Global Variables:
56 *
57 * None
58 *
59 * Arguments:
60 *
61 * int argc; The number of arguments
62 * char *argv[]; The command line arguments
63 *
64 * Return Values:
65 *
66 * 0 - the file was move successfully
67 * an error occurred.
68 *
69 * Author: Keith W. Sheffield
70 * Date: 03/20/2002
71 *
72 * Modification History:
73 *
74 * MM/DD/YY Name Description
75 */
76 int
main_e2mv(int argc,char * argv[])77 main_e2mv(int argc, char *argv[])
78 {
79 int verbose=0;
80 int force=0;
81 int swap_files=0;
82 int errcnt=0;
83 char *cur_filesys = NULL;
84 ext2_filsys fs = NULL;
85 ext2_ino_t root;
86 ext2_ino_t srcd;
87 ext2_ino_t destd;
88 ext2_ino_t source_file;
89 char *src_dir;
90 char *dest_dir;
91 char *src_name;
92 char *dest_name;
93 char *result_name;
94 long retval;
95 int c;
96 int curidx;
97
98 #ifdef HAVE_OPTRESET
99 optreset = 1; /* Makes BSD getopt happy */
100 #endif
101 while ((c = getopt(argc, argv, "vfs")) != EOF)
102 {
103 switch (c)
104 {
105 case 'v':
106 verbose = 1;
107 break;
108 case 'f':
109 force = E2T_FORCE;
110 break;
111 case 's':
112 swap_files = 1;
113 break;
114 default:
115 errcnt++;
116 break;
117 }
118 }
119
120 curidx = optind;
121
122 force |= E2T_DO_MV;
123
124 if (errcnt || argc < curidx+2)
125 {
126 fputs(USAGE, stderr);
127 return(1);
128 }
129
130 if (swap_files)
131 return(do_swap(force, verbose, curidx, argc, argv));
132
133 cur_filesys = argv[curidx++];
134 if (NULL == (src_dir = strchr(cur_filesys, ':')))
135 {
136 fprintf(stderr, "Invalid file specification: %s\n", cur_filesys);
137 return(1);
138 }
139 *src_dir++ = '\0';
140
141 if ((retval = open_filesystem(cur_filesys, &fs, &root, 1)))
142 {
143 return retval;
144 }
145
146
147 /* get the destination directory */
148 dest_name = NULL;
149 if (strcmp(dest_dir = argv[argc-1], ".") != 0)
150 {
151 /* check to see if the file name already exists in the current
152 * directory and also see if it is a directory.
153 */
154 if ((retval = ext2fs_namei(fs, root, root, dest_dir, &destd)) ||
155 (retval = ext2fs_check_directory(fs, destd)))
156 {
157 if (retval != EXT2_ET_FILE_NOT_FOUND &&
158 retval != EXT2_ET_NO_DIRECTORY)
159 {
160 fprintf(stderr, "%s\n",error_message(retval));
161 ext2fs_close(fs);
162 return(retval);
163 }
164
165 /* ok, so it's either not there or it's not a directory, so
166 * get the real destination directory and file name.
167 */
168 if (curidx+1 < argc)
169 {
170 fprintf(stderr, "%s must be a directory!\n", dest_dir);
171 ext2fs_close(fs);
172 return(1);
173 }
174
175 if (get_file_parts(fs, root, dest_dir, &destd, &dest_dir,
176 &dest_name))
177 {
178 ext2fs_close(fs);
179 return(-1);
180 }
181 }
182 else /* we have a directory!!! */
183 dest_name = NULL;
184 }
185 else
186 {
187 destd = root;
188 dest_name = NULL;
189 }
190
191 do
192 {
193 /* move to the source directory */
194 if (get_file_parts(fs, root, src_dir, &srcd, &src_dir, &src_name))
195 {
196 ext2fs_close(fs);
197 return(-1);
198 }
199
200 /* get the inode number for the source file */
201 if ((retval = ext2fs_namei(fs, srcd, srcd, src_name, &source_file)))
202 {
203 fprintf(stderr, "%s: source file %s\n",error_message(retval),
204 src_name);
205 ext2fs_close(fs);
206 return(retval);
207 }
208
209 result_name = (dest_name) ? dest_name : src_name;
210
211 /* now create the link */
212 if ((retval = create_hard_link(fs, destd, source_file, result_name,
213 force)))
214 {
215 fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
216 ((src_dir == NULL) ? "." : src_dir), src_name,
217 ((dest_dir == NULL) ? "." : dest_dir), result_name);
218 ext2fs_close(fs);
219 return(1);
220 }
221
222 if ((retval = ext2fs_unlink(fs, srcd, src_name, 0, 0)))
223 {
224 fprintf(stderr, "%s - %s\n", src_name, error_message(retval));
225 ext2fs_close(fs);
226 return(retval);
227 }
228
229 if (verbose)
230 fprintf(stderr, "moved %s/%s as %s/%s\n",
231 ((src_dir == NULL) ? "." : src_dir), src_name,
232 ((dest_dir == NULL) ? "." : dest_dir), result_name);
233 src_dir = argv[curidx++];
234 }
235 while (curidx < argc);
236
237 ext2fs_close(fs);
238 return(0);
239
240 } /* end of do_mv */
241
242 /* Name: get_file_parts()
243 *
244 * Description:
245 *
246 * This function returns each of the following file 'parts': directory name,
247 * base name, inode number of the directory
248 *
249 * Algorithm:
250 *
251 * Use the root directory as the current working directory
252 * Find the last / in the full pathname
253 * If none are found, set the basename to the full pathname,
254 * and the directory to NULL
255 * Otherwise,
256 * Separate the basename from the directory
257 * Change the working directory
258 * Set the return pointers.
259 *
260 * Global Variables:
261 *
262 * None.
263 *
264 * Arguments:
265 *
266 * ext2_filsys fs; the filesystem being used
267 * ext2_ino_t root; the root directory of the filesystem
268 * char *pathname; the full pathname of the file
269 * ext2_ino_t *dir_ino; The inode number of the directory
270 * char **dir_name; the directory the file is in
271 * char **base_name; The basename of the file
272 *
273 * Return Values:
274 *
275 * 0 - retrieved the information ok
276 * otherwise the error code of what went wrong
277 *
278 * Author: Keith W. Sheffield
279 * Date: 03/21/2002
280 *
281 * Modification History:
282 *
283 * MM/DD/YY Name Description
284 *
285 */
286 long
get_file_parts(ext2_filsys fs,ext2_ino_t root,char * pathname,ext2_ino_t * dir_ino,char ** dir_name,char ** base_name)287 get_file_parts(ext2_filsys fs, ext2_ino_t root, char *pathname,
288 ext2_ino_t *dir_ino, char **dir_name, char **base_name)
289 {
290 char *fname;
291 long retval;
292
293 /* move to the source directory */
294 *dir_name = pathname;
295 *dir_ino = root;
296 if (NULL == (fname = strrchr(pathname, '/')))
297 {
298 fname = pathname;
299 *dir_name = NULL;
300 }
301 else
302 {
303 *fname++ = '\0';
304 if ((*pathname != '\0' && strcmp(pathname, ".") != 0) &&
305 (retval = change_cwd(fs, root, dir_ino, pathname)))
306 {
307 fprintf(stderr, "Error changing to directory %s\n",
308 pathname);
309 return(retval);
310 }
311 }
312
313 *base_name = fname;
314 return(0);
315 } /* end of get_file_parts */
316
317
318 /* Name: do_swap()
319 *
320 * Description:
321 *
322 * This function swaps the names of two files and optionally assigns the
323 * first file a new name:
324 *
325 * file1 file2 file3
326 *
327 * After the operation, file1 will reference the file that was originally file2, and file3 will reference the what used to be file1.
328 *
329 * Algorithm:
330 *
331 * check input parameters
332 * Get the directory and inode numbers for the first two files
333 * If a third file exists
334 * Get the directory info for the file
335 * Rename the first file to the third
336 * Rename the 2nd file to the first
337 * Otherwise
338 * Remove the first file from its directory
339 * Rename the 2nd file to the first
340 * Add the first file back as the 2nd file.
341 *
342 * Global Variables:
343 *
344 * None.
345 *
346 * Arguments:
347 *
348 * int force; Flag indicating if existing files are to be removed
349 * int verbose; Flag to print lots of output
350 * int curidx; The current index in the command line args
351 * int argc; The total number of arguments
352 * char **argv; Pointer to an array of argument strings.
353 *
354 * Return Values:
355 *
356 * 0 - the operation was successful
357 * otherwise the error code of what went wrong.
358 *
359 * Author: Keith W. Sheffield
360 * Date: 03/21/2002
361 *
362 * Modification History:
363 *
364 * MM/DD/YY Name Description
365 *
366 */
367
368 static long
do_swap(int force,int verbose,int curidx,int argc,char ** argv)369 do_swap(int force, int verbose, int curidx, int argc, char **argv)
370 {
371 char *cur_filesys = NULL;
372 ext2_filsys fs = NULL;
373 ext2_ino_t root;
374 ext2_ino_t file1_dirno;
375 ext2_ino_t file2_dirno;
376 ext2_ino_t file3_dirno;
377 ext2_ino_t file1_no;
378 ext2_ino_t file2_no;
379 char *file1_dir;
380 char *file2_dir;
381 char *file3_dir;
382 char *file1_name;
383 char *file2_name;
384 char *file3_name;
385 long retval;
386
387 if (curidx + 2 > argc)
388 {
389 fputs(USAGE, stderr);
390 return(1);
391 }
392
393 cur_filesys = argv[curidx++];
394 if (NULL == (file1_dir = strchr(cur_filesys, ':')))
395 {
396 fprintf(stderr, "Invalid file specification: %s\n", cur_filesys);
397 return(1);
398 }
399 *file1_dir++ = '\0';
400
401 if ((retval = open_filesystem(cur_filesys, &fs, &root, 1)))
402 {
403 return retval;
404 }
405
406 /* move to the file 1 directory */
407 if (get_file_parts(fs, root, file1_dir, &file1_dirno, &file1_dir,
408 &file1_name))
409 {
410 ext2fs_close(fs);
411 return(-1);
412 }
413
414 /* get the inode number for the file 1 file */
415 if ((retval = ext2fs_namei(fs, file1_dirno, file1_dirno, file1_name,
416 &file1_no)))
417 {
418 fprintf(stderr, "%s: file 1 file %s\n",error_message(retval),
419 file1_name);
420 ext2fs_close(fs);
421 return(retval);
422 }
423
424
425 /* move to the file 2 directory */
426 if (get_file_parts(fs, root, argv[curidx++], &file2_dirno, &file2_dir,
427 &file2_name))
428 {
429 ext2fs_close(fs);
430 return(-1);
431 }
432
433 /* get the inode number for the file 2 file */
434 if ((retval = ext2fs_namei(fs, file2_dirno, file2_dirno, file2_name,
435 &file2_no)))
436 {
437 fprintf(stderr, "%s: file 2 file %s\n",error_message(retval),
438 file2_name);
439 ext2fs_close(fs);
440 return(retval);
441 }
442
443 if (curidx < argc)
444 {
445 /* move to the file 3 directory */
446 if (get_file_parts(fs, root, argv[curidx++], &file3_dirno, &file3_dir,
447 &file3_name))
448 {
449 ext2fs_close(fs);
450 return(-1);
451 }
452
453 /* now move the first file to the 3rd */
454 if ((retval = create_hard_link(fs, file3_dirno, file1_no, file3_name,
455 force)))
456 {
457 fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
458 ((file1_dir == NULL) ? "." : file1_dir), file1_name,
459 ((file3_dir == NULL) ? "." : file3_dir), file3_name);
460 ext2fs_close(fs);
461 return(1);
462 }
463
464 if ((retval = ext2fs_unlink(fs, file1_dirno, file1_name, 0, 0)))
465 {
466 fprintf(stderr, "%s - %s\n", file1_name, error_message(retval));
467 ext2fs_close(fs);
468 return(retval);
469 }
470
471
472 /* now move the 2nd file to the 1st */
473 if ((retval = create_hard_link(fs, file1_dirno, file2_no, file1_name,
474 force)))
475 {
476 fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
477 ((file2_dir == NULL) ? "." : file2_dir), file2_name,
478 ((file1_dir == NULL) ? "." : file1_dir), file1_name);
479 ext2fs_close(fs);
480 return(1);
481 }
482
483 if ((retval = ext2fs_unlink(fs, file2_dirno, file2_name, 0, 0)))
484 {
485 fprintf(stderr, "%s - %s\n", file2_name, error_message(retval));
486 ext2fs_close(fs);
487 return(retval);
488 }
489
490 if (verbose)
491 fprintf(stderr, "renamed file %s/%s as %s/%s\n"
492 "renamed file %s/%s as %s/%s\n",
493 ((file1_dir == NULL) ? "." : file1_dir), file1_name,
494 ((file3_dir == NULL) ? "." : file3_dir), file3_name,
495 ((file2_dir == NULL) ? "." : file2_dir), file2_name,
496 ((file1_dir == NULL) ? "." : file1_dir), file1_name);
497 }
498 else
499 {
500 /* now remove the first file */
501 if ((retval = ext2fs_unlink(fs, file1_dirno, file1_name, 0, 0)))
502 {
503 fprintf(stderr, "%s - %s\n", file1_name, error_message(retval));
504 ext2fs_close(fs);
505 return(retval);
506 }
507
508 /* now move the 2nd file to the 1st */
509 if ((retval = create_hard_link(fs, file1_dirno, file2_no, file1_name,
510 force)))
511 {
512 fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
513 ((file2_dir == NULL) ? "." : file2_dir), file2_name,
514 ((file1_dir == NULL) ? "." : file1_dir), file1_name);
515 ext2fs_close(fs);
516 return(1);
517 }
518
519 if ((retval = ext2fs_unlink(fs, file2_dirno, file2_name, 0, 0)))
520 {
521 fprintf(stderr, "%s - %s\n", file2_name, error_message(retval));
522 ext2fs_close(fs);
523 return(retval);
524 }
525
526 if ((retval = create_hard_link(fs, file2_dirno, file1_no, file2_name,
527 force)))
528 {
529 fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
530 ((file1_dir == NULL) ? "." : file1_dir), file1_name,
531 ((file2_dir == NULL) ? "." : file2_dir), file2_name);
532 ext2fs_close(fs);
533 return(1);
534 }
535
536 if (verbose)
537 fprintf(stderr, "swapped files %s/%s <-> %s/%s\n",
538 ((file1_dir == NULL) ? "." : file1_dir), file1_name,
539 ((file2_dir == NULL) ? "." : file2_dir), file2_name);
540
541 }
542
543 ext2fs_close(fs);
544 return(0);
545
546 } /* end of do_swap */
547