37
37
#include <assert.h>
38
38
#include <ctype.h>
39
39
#include <sys/debug.h>
40
+ #include <dirent.h>
40
41
#include <errno.h>
41
42
#include <getopt.h>
42
43
#include <libgen.h>
@@ -121,6 +122,7 @@ static int zfs_do_change_key(int argc, char **argv);
121
122
static int zfs_do_project (int argc , char * * argv );
122
123
static int zfs_do_version (int argc , char * * argv );
123
124
static int zfs_do_redact (int argc , char * * argv );
125
+ static int zfs_do_rewrite (int argc , char * * argv );
124
126
static int zfs_do_wait (int argc , char * * argv );
125
127
126
128
#ifdef __FreeBSD__
@@ -193,6 +195,7 @@ typedef enum {
193
195
HELP_CHANGE_KEY ,
194
196
HELP_VERSION ,
195
197
HELP_REDACT ,
198
+ HELP_REWRITE ,
196
199
HELP_JAIL ,
197
200
HELP_UNJAIL ,
198
201
HELP_WAIT ,
@@ -227,7 +230,7 @@ static zfs_command_t command_table[] = {
227
230
{ "promote" , zfs_do_promote , HELP_PROMOTE },
228
231
{ "rename" , zfs_do_rename , HELP_RENAME },
229
232
{ "bookmark" , zfs_do_bookmark , HELP_BOOKMARK },
230
- { "program" , zfs_do_channel_program , HELP_CHANNEL_PROGRAM },
233
+ { "diff" , zfs_do_diff , HELP_DIFF },
231
234
{ NULL },
232
235
{ "list" , zfs_do_list , HELP_LIST },
233
236
{ NULL },
@@ -249,27 +252,31 @@ static zfs_command_t command_table[] = {
249
252
{ NULL },
250
253
{ "send" , zfs_do_send , HELP_SEND },
251
254
{ "receive" , zfs_do_receive , HELP_RECEIVE },
255
+ { "redact" , zfs_do_redact , HELP_REDACT },
252
256
{ NULL },
253
257
{ "allow" , zfs_do_allow , HELP_ALLOW },
254
- { NULL },
255
258
{ "unallow" , zfs_do_unallow , HELP_UNALLOW },
256
259
{ NULL },
257
260
{ "hold" , zfs_do_hold , HELP_HOLD },
258
261
{ "holds" , zfs_do_holds , HELP_HOLDS },
259
262
{ "release" , zfs_do_release , HELP_RELEASE },
260
- { "diff" , zfs_do_diff , HELP_DIFF },
263
+ { NULL },
261
264
{ "load-key" , zfs_do_load_key , HELP_LOAD_KEY },
262
265
{ "unload-key" , zfs_do_unload_key , HELP_UNLOAD_KEY },
263
266
{ "change-key" , zfs_do_change_key , HELP_CHANGE_KEY },
264
- { "redact" , zfs_do_redact , HELP_REDACT },
267
+ { NULL },
268
+ { "program" , zfs_do_channel_program , HELP_CHANNEL_PROGRAM },
269
+ { "rewrite" , zfs_do_rewrite , HELP_REWRITE },
265
270
{ "wait" , zfs_do_wait , HELP_WAIT },
266
271
267
272
#ifdef __FreeBSD__
273
+ { NULL },
268
274
{ "jail" , zfs_do_jail , HELP_JAIL },
269
275
{ "unjail" , zfs_do_unjail , HELP_UNJAIL },
270
276
#endif
271
277
272
278
#ifdef __linux__
279
+ { NULL },
273
280
{ "zone" , zfs_do_zone , HELP_ZONE },
274
281
{ "unzone" , zfs_do_unzone , HELP_UNZONE },
275
282
#endif
@@ -432,6 +439,9 @@ get_usage(zfs_help_t idx)
432
439
case HELP_REDACT :
433
440
return (gettext ("\tredact <snapshot> <bookmark> "
434
441
"<redaction_snapshot> ...\n" ));
442
+ case HELP_REWRITE :
443
+ return (gettext ("\trewrite [-r] [-o <offset>] [-l <length>] "
444
+ "<directory|file ...>\n" ));
435
445
case HELP_JAIL :
436
446
return (gettext ("\tjail <jailid|jailname> <filesystem>\n" ));
437
447
case HELP_UNJAIL :
@@ -9016,6 +9026,159 @@ zfs_do_project(int argc, char **argv)
9016
9026
return (ret );
9017
9027
}
9018
9028
9029
+ static int
9030
+ zfs_rewrite_file (const char * path , zfs_rewrite_args_t * args )
9031
+ {
9032
+ int fd , ret = 0 ;
9033
+
9034
+ fd = open (path , O_WRONLY );
9035
+ if (fd < 0 ) {
9036
+ ret = errno ;
9037
+ (void ) fprintf (stderr , gettext ("failed to open %s: %s\n" ),
9038
+ path , strerror (errno ));
9039
+ return (ret );
9040
+ }
9041
+
9042
+ if (ioctl (fd , ZFS_IOC_REWRITE , args ) < 0 ) {
9043
+ ret = errno ;
9044
+ (void ) fprintf (stderr , gettext ("failed to rewrite %s: %s\n" ),
9045
+ path , strerror (errno ));
9046
+ }
9047
+
9048
+ close (fd );
9049
+ return (ret );
9050
+ }
9051
+
9052
+ static int
9053
+ zfs_rewrite_dir (const char * path , zfs_rewrite_args_t * args , nvlist_t * dirs )
9054
+ {
9055
+ struct dirent * ent ;
9056
+ DIR * dir ;
9057
+ int ret = 0 , err ;
9058
+
9059
+ dir = opendir (path );
9060
+ if (dir == NULL ) {
9061
+ if (errno == ENOENT )
9062
+ return (0 );
9063
+ (void ) fprintf (stderr , gettext ("failed to opendir %s: %s\n" ),
9064
+ path , strerror (errno ));
9065
+ return (errno );
9066
+ }
9067
+
9068
+ size_t plen = strlen (path ) + 1 ;
9069
+ while ((ent = readdir (dir )) != NULL ) {
9070
+ char * fullname ;
9071
+
9072
+ if (strcmp (ent -> d_name , "." ) == 0 ||
9073
+ strcmp (ent -> d_name , ".." ) == 0 )
9074
+ continue ;
9075
+
9076
+ if (plen + strlen (ent -> d_name ) >= PATH_MAX ) {
9077
+ (void ) fprintf (stderr , gettext ("path too long %s/%s\n" ),
9078
+ path , ent -> d_name );
9079
+ ret = ENAMETOOLONG ;
9080
+ continue ;
9081
+ }
9082
+
9083
+ if (asprintf (& fullname , "%s/%s" , path , ent -> d_name ) == -1 ) {
9084
+ (void ) fprintf (stderr ,
9085
+ gettext ("failed to allocate memory\n" ));
9086
+ ret = ENOMEM ;
9087
+ continue ;
9088
+ }
9089
+
9090
+ if (ent -> d_type == DT_REG ) {
9091
+ err = zfs_rewrite_file (fullname , args );
9092
+ if (err )
9093
+ ret = err ;
9094
+ } else if (ent -> d_type == DT_DIR )
9095
+ fnvlist_add_boolean (dirs , fullname );
9096
+
9097
+ free (fullname );
9098
+ }
9099
+
9100
+ closedir (dir );
9101
+ return (ret );
9102
+ }
9103
+
9104
+ static int
9105
+ zfs_rewrite_path (const char * path , boolean_t recurse , zfs_rewrite_args_t * args ,
9106
+ nvlist_t * dirs )
9107
+ {
9108
+ struct stat st ;
9109
+
9110
+ int ret = stat (path , & st );
9111
+ if (ret ) {
9112
+ (void ) fprintf (stderr , gettext ("failed to stat %s: %s\n" ),
9113
+ path , strerror (errno ));
9114
+ return (ret );
9115
+ }
9116
+
9117
+ if (S_ISREG (st .st_mode ))
9118
+ ret = zfs_rewrite_file (path , args );
9119
+ else if (S_ISDIR (st .st_mode ) && recurse )
9120
+ ret = zfs_rewrite_dir (path , args , dirs );
9121
+ return (ret );
9122
+ }
9123
+
9124
+ static int
9125
+ zfs_do_rewrite (int argc , char * * argv )
9126
+ {
9127
+ int ret = 0 , err , c ;
9128
+ boolean_t recurse = B_FALSE ;
9129
+
9130
+ if (argc < 2 )
9131
+ usage (B_FALSE );
9132
+
9133
+ zfs_rewrite_args_t args ;
9134
+ args .off = 0 ;
9135
+ args .len = 0 ;
9136
+ args .flags = 0 ;
9137
+
9138
+ while ((c = getopt (argc , argv , "ro:l:" )) != -1 ) {
9139
+ switch (c ) {
9140
+ case 'r' :
9141
+ recurse = B_TRUE ;
9142
+ break ;
9143
+ case 'o' :
9144
+ args .off = strtoll (optarg , NULL , 0 );
9145
+ break ;
9146
+ case 'l' :
9147
+ args .len = strtoll (optarg , NULL , 0 );
9148
+ break ;
9149
+ default :
9150
+ (void ) fprintf (stderr , gettext ("invalid option '%c'\n" ),
9151
+ optopt );
9152
+ usage (B_FALSE );
9153
+ }
9154
+ }
9155
+
9156
+ argv += optind ;
9157
+ argc -= optind ;
9158
+ if (argc == 0 ) {
9159
+ (void ) fprintf (stderr ,
9160
+ gettext ("missing file or directory target(s)\n" ));
9161
+ usage (B_FALSE );
9162
+ }
9163
+
9164
+ nvlist_t * dirs = fnvlist_alloc ();
9165
+ for (int i = 0 ; i < argc ; i ++ ) {
9166
+ err = zfs_rewrite_path (argv [i ], recurse , & args , dirs );
9167
+ if (err )
9168
+ ret = err ;
9169
+ }
9170
+ nvpair_t * dir ;
9171
+ while ((dir = nvlist_next_nvpair (dirs , NULL )) != NULL ) {
9172
+ err = zfs_rewrite_dir (nvpair_name (dir ), & args , dirs );
9173
+ if (err )
9174
+ ret = err ;
9175
+ fnvlist_remove_nvpair (dirs , dir );
9176
+ }
9177
+ fnvlist_free (dirs );
9178
+
9179
+ return (ret );
9180
+ }
9181
+
9019
9182
static int
9020
9183
zfs_do_wait (int argc , char * * argv )
9021
9184
{
0 commit comments