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 [-rx] [-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,192 @@ 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 , boolean_t verbose , 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
+ } else if (verbose ) {
9047
+ printf ("%s\n" , path );
9048
+ }
9049
+
9050
+ close (fd );
9051
+ return (ret );
9052
+ }
9053
+
9054
+ static int
9055
+ zfs_rewrite_dir (const char * path , boolean_t verbose , boolean_t xdev , dev_t dev ,
9056
+ zfs_rewrite_args_t * args , nvlist_t * dirs )
9057
+ {
9058
+ struct dirent * ent ;
9059
+ DIR * dir ;
9060
+ int ret = 0 , err ;
9061
+
9062
+ dir = opendir (path );
9063
+ if (dir == NULL ) {
9064
+ if (errno == ENOENT )
9065
+ return (0 );
9066
+ ret = errno ;
9067
+ (void ) fprintf (stderr , gettext ("failed to opendir %s: %s\n" ),
9068
+ path , strerror (errno ));
9069
+ return (ret );
9070
+ }
9071
+
9072
+ size_t plen = strlen (path ) + 1 ;
9073
+ while ((ent = readdir (dir )) != NULL ) {
9074
+ char * fullname ;
9075
+ struct stat st ;
9076
+
9077
+ if (ent -> d_type != DT_REG && ent -> d_type != DT_DIR )
9078
+ continue ;
9079
+
9080
+ if (strcmp (ent -> d_name , "." ) == 0 ||
9081
+ strcmp (ent -> d_name , ".." ) == 0 )
9082
+ continue ;
9083
+
9084
+ if (plen + strlen (ent -> d_name ) >= PATH_MAX ) {
9085
+ (void ) fprintf (stderr , gettext ("path too long %s/%s\n" ),
9086
+ path , ent -> d_name );
9087
+ ret = ENAMETOOLONG ;
9088
+ continue ;
9089
+ }
9090
+
9091
+ if (asprintf (& fullname , "%s/%s" , path , ent -> d_name ) == -1 ) {
9092
+ (void ) fprintf (stderr ,
9093
+ gettext ("failed to allocate memory\n" ));
9094
+ ret = ENOMEM ;
9095
+ continue ;
9096
+ }
9097
+
9098
+ if (xdev ) {
9099
+ if (stat (fullname , & st ) < 0 ) {
9100
+ ret = errno ;
9101
+ (void ) fprintf (stderr ,
9102
+ gettext ("failed to stat %s: %s\n" ),
9103
+ fullname , strerror (errno ));
9104
+ free (fullname );
9105
+ continue ;
9106
+ }
9107
+ if (st .st_dev != dev ) {
9108
+ free (fullname );
9109
+ continue ;
9110
+ }
9111
+ }
9112
+
9113
+ if (ent -> d_type == DT_REG ) {
9114
+ err = zfs_rewrite_file (fullname , verbose , args );
9115
+ if (err )
9116
+ ret = err ;
9117
+ } else { /* DT_DIR */
9118
+ fnvlist_add_uint64 (dirs , fullname , dev );
9119
+ }
9120
+
9121
+ free (fullname );
9122
+ }
9123
+
9124
+ closedir (dir );
9125
+ return (ret );
9126
+ }
9127
+
9128
+ static int
9129
+ zfs_rewrite_path (const char * path , boolean_t verbose , boolean_t recurse ,
9130
+ boolean_t xdev , zfs_rewrite_args_t * args , nvlist_t * dirs )
9131
+ {
9132
+ struct stat st ;
9133
+ int ret = 0 ;
9134
+
9135
+ if (stat (path , & st ) < 0 ) {
9136
+ ret = errno ;
9137
+ (void ) fprintf (stderr , gettext ("failed to stat %s: %s\n" ),
9138
+ path , strerror (errno ));
9139
+ return (ret );
9140
+ }
9141
+
9142
+ if (S_ISREG (st .st_mode )) {
9143
+ ret = zfs_rewrite_file (path , verbose , args );
9144
+ } else if (S_ISDIR (st .st_mode ) && recurse ) {
9145
+ ret = zfs_rewrite_dir (path , verbose , xdev , st .st_dev , args ,
9146
+ dirs );
9147
+ }
9148
+ return (ret );
9149
+ }
9150
+
9151
+ static int
9152
+ zfs_do_rewrite (int argc , char * * argv )
9153
+ {
9154
+ int ret = 0 , err , c ;
9155
+ boolean_t recurse = B_FALSE , verbose = B_FALSE , xdev = B_FALSE ;
9156
+
9157
+ if (argc < 2 )
9158
+ usage (B_FALSE );
9159
+
9160
+ zfs_rewrite_args_t args ;
9161
+ memset (& args , 0 , sizeof (args ));
9162
+
9163
+ while ((c = getopt (argc , argv , "l:o:rvx" )) != -1 ) {
9164
+ switch (c ) {
9165
+ case 'l' :
9166
+ args .len = strtoll (optarg , NULL , 0 );
9167
+ break ;
9168
+ case 'o' :
9169
+ args .off = strtoll (optarg , NULL , 0 );
9170
+ break ;
9171
+ case 'r' :
9172
+ recurse = B_TRUE ;
9173
+ break ;
9174
+ case 'v' :
9175
+ verbose = B_TRUE ;
9176
+ break ;
9177
+ case 'x' :
9178
+ xdev = B_TRUE ;
9179
+ break ;
9180
+ default :
9181
+ (void ) fprintf (stderr , gettext ("invalid option '%c'\n" ),
9182
+ optopt );
9183
+ usage (B_FALSE );
9184
+ }
9185
+ }
9186
+
9187
+ argv += optind ;
9188
+ argc -= optind ;
9189
+ if (argc == 0 ) {
9190
+ (void ) fprintf (stderr ,
9191
+ gettext ("missing file or directory target(s)\n" ));
9192
+ usage (B_FALSE );
9193
+ }
9194
+
9195
+ nvlist_t * dirs = fnvlist_alloc ();
9196
+ for (int i = 0 ; i < argc ; i ++ ) {
9197
+ err = zfs_rewrite_path (argv [i ], verbose , recurse , xdev , & args ,
9198
+ dirs );
9199
+ if (err )
9200
+ ret = err ;
9201
+ }
9202
+ nvpair_t * dir ;
9203
+ while ((dir = nvlist_next_nvpair (dirs , NULL )) != NULL ) {
9204
+ err = zfs_rewrite_dir (nvpair_name (dir ), verbose , xdev ,
9205
+ fnvpair_value_uint64 (dir ), & args , dirs );
9206
+ if (err )
9207
+ ret = err ;
9208
+ fnvlist_remove_nvpair (dirs , dir );
9209
+ }
9210
+ fnvlist_free (dirs );
9211
+
9212
+ return (ret );
9213
+ }
9214
+
9019
9215
static int
9020
9216
zfs_do_wait (int argc , char * * argv )
9021
9217
{
0 commit comments