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