11/*
2- Copyright (C) 2013-2023 Chromebrew Authors
2+ Copyright (C) 2013-2024 Chromebrew Authors
33
44 This program is free software: you can redistribute it and/or modify
55 it under the terms of the GNU General Public License as published by
1515 along with this program. If not, see https://www.gnu.org/licenses/gpl-3.0.html.
1616*/
1717
18- /*
19- crew-mvdir: Move all files under one directory to another,
20- override conflict files in the destination directory (merge two directories)
21-
22- Equivalent of `rsync -ahHAXW --remove-source-files dir1/ dir2/`
23-
24- crew-mvdir use rename() syscall to move files (instead of copying-deleting), that's why it is faster than `rsync`
25-
26- Usage: ./crew-mvdir [-v] [-n] [src] [dst]
27-
28- cc ./crew-mvdir.c -O2 -o crew-mvdir
29- */
30-
3118#define _XOPEN_SOURCE 700 // for nftw()
3219#include <stdio.h>
3320#include <stdlib.h>
3421#include <stdbool.h>
3522#include <fcntl.h>
3623#include <unistd.h>
3724#include <errno.h>
38- #include <limits.h>
3925#include <string.h>
4026#include <ftw.h>
4127#include <sys/sendfile.h>
4228#include <sys/stat.h>
29+ #include "./mvdir.h"
4330
44- bool same_fs = true, verbose = false, no_clobber = false;
45- char src [PATH_MAX ], dst [PATH_MAX ];
31+ struct mvdir_opts * opts ;
4632
4733void copy_and_delete_file (const struct stat * src_info , const char * src_path , const char * dst_path ) {
4834 // copy_and_delete_file(): copy a file and delete it after copying, used as a fallback when rename() does not work
@@ -77,34 +63,34 @@ void copy_and_delete_file(const struct stat *src_info, const char *src_path, con
7763int move_file (const char * src_path , const struct stat * src_info , int flag , struct FTW * ftwbuf ) {
7864 char dst_path [PATH_MAX ];
7965
80- strcpy (dst_path , dst );
81- strcat (dst_path , src_path + strlen (src ));
66+ strcpy (dst_path , opts -> dst );
67+ strcat (dst_path , src_path + strlen (opts -> src ));
8268
8369 if (strcmp (src_path , "." ) == 0 ) return 0 ;
84- if (verbose ) fprintf (stderr , "%s -> %s\n" , src_path , dst_path );
70+ if (opts -> verbose ) fprintf (stderr , "%s -> %s\n" , src_path , dst_path );
8571
8672 switch (flag ) {
8773 case FTW_F :
8874 case FTW_SL :
8975 case FTW_SLN :
9076 if (access (dst_path , F_OK ) == 0 ) {
9177 // do not touch existing files if -n specified
92- if (!(no_clobber || remove (dst_path ) == 0 )) {
78+ if (!(opts -> no_clobber || remove (dst_path ) == 0 )) {
9379 // remove file with same name in dest (if exist)
9480 fprintf (stderr , "%s: failed to remove file: %s\n" , dst_path , strerror (errno ));
9581 exit (errno );
9682 }
9783 }
9884
9985 // move (rename) file to dest
100- if (same_fs ) {
86+ if (opts -> same_fs ) {
10187 // (when source and destination are in the same filesystem)
10288 // file/symlink: move file to dest, override files with same filename in dest (mode/owner remain unchanged)
10389 if (rename (src_path , dst_path ) == -1 ) {
10490 if (errno == EXDEV ) {
10591 // fallback to copying-deleting if source and destination are not in the same filesystem
106- same_fs = false;
107- if (verbose ) fprintf (stderr , "Warning: destination is not in the same filesystem, will fallback to sendfile() instead.\n" );
92+ opts -> same_fs = false;
93+ if (opts -> verbose ) fprintf (stderr , "Warning: destination is not in the same filesystem, will fallback to sendfile() instead.\n" );
10894 return move_file (src_path , src_info , flag , ftwbuf );
10995 }
11096
@@ -142,7 +128,7 @@ int move_file(const char *src_path, const struct stat *src_info, int flag, struc
142128 if (access (dst_path , F_OK ) == -1 ) {
143129 mode_t dir_mode = src_info -> st_mode ;
144130
145- if (verbose ) fprintf (stderr , "Creating directory %s\n" , dst_path );
131+ if (opts -> verbose ) fprintf (stderr , "Creating directory %s\n" , dst_path );
146132 if (mkdir (dst_path , dir_mode ) == -1 ) {
147133 fprintf (stderr , "%s: mkdir() failed: %s\n" , src_path , strerror (errno ));
148134 exit (errno );
@@ -158,50 +144,23 @@ int move_file(const char *src_path, const struct stat *src_info, int flag, struc
158144 return 0 ;
159145}
160146
161- int main (int argc , char * * argv ) {
162- int opt ;
163-
164- while ((opt = getopt (argc , argv , "vn" )) != -1 ) {
165- switch (opt ) {
166- case 'v' :
167- // verbose mode
168- verbose = true;
169- break ;
170- case 'n' :
171- // do not overwrite an existing file
172- no_clobber = true;
173- break ;
174- default :
175- fprintf (stderr , "Usage: %s [-v] [-n] [src] [dst]\n" , argv [0 ]);
176- exit (EXIT_FAILURE );
177- break ;
178- }
179- }
180-
181- if (argc - optind != 2 ) {
182- fprintf (stderr , "Usage: %s [-v] [-n] [src] [dst]\n" , argv [0 ]);
183- exit (EXIT_FAILURE );
184- }
185-
186- strcpy (src , argv [optind ]);
187- strcpy (dst , argv [optind + 1 ]);
188-
189- struct stat src_info , dst_info ;
190- stat (src , & src_info );
191- stat (dst , & dst_info );
147+ int move_directory (struct mvdir_opts * optPtr ) {
148+ opts = optPtr ;
192149
193150 // trailing slashes in path are required in order to make move_file() works
194- int src_len = strlen (src ),
195- dst_len = strlen (dst );
151+ int src_len = strlen (opts -> src ),
152+ dst_len = strlen (opts -> dst );
196153
197- if (src [src_len - 1 ] != '/' ) src [src_len ] = '/' ;
198- if (dst [dst_len - 1 ] != '/' ) dst [dst_len ] = '/' ;
154+ if (opts -> src [src_len - 1 ] != '/' ) opts -> src [src_len ] = '/' ;
155+ if (opts -> dst [dst_len - 1 ] != '/' ) opts -> dst [dst_len ] = '/' ;
199156
200157 // call move_file() with files in src recursively
201- if (nftw (src , move_file , 100 , FTW_PHYS | FTW_MOUNT ) == -1 ) {
202- fprintf (stderr , "%s: nftw() failed: %s\n" , src , strerror (errno ));
158+ int ret = nftw (opts -> src , move_file , 100 , FTW_PHYS | FTW_MOUNT );
159+
160+ if (ret == -1 ) {
161+ fprintf (stderr , "%s: nftw() failed: %s\n" , opts -> src , strerror (errno ));
203162 exit (errno );
204163 }
205164
206- return 0 ;
207- }
165+ return ret ;
166+ }
0 commit comments