Index: findutils-4.2.28/find/parser.c =================================================================== --- findutils-4.2.28.orig/find/parser.c 2006-11-09 00:44:19.051030424 -0800 +++ findutils-4.2.28/find/parser.c 2006-11-09 00:50:07.350127617 -0800 @@ -134,6 +134,7 @@ static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); +static boolean parse_sparse PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); @@ -270,6 +271,7 @@ PARSE_OPTION ("regextype", regextype), /* GNU */ PARSE_TEST ("samefile", samefile), /* GNU */ PARSE_TEST ("size", size), + PARSE_TEST ("sparse", sparse), /* GNU */ PARSE_TEST ("type", type), PARSE_TEST ("uid", uid), /* GNU */ PARSE_TEST ("used", used), /* GNU */ @@ -1601,6 +1603,15 @@ return true; } +static boolean +parse_sparse (const struct parser_table* entry, char **argv, int *arg_ptr) +{ + (void) argv; + (void) arg_ptr; + + insert_primary (entry); + return true; +} static boolean parse_true (const struct parser_table* entry, char **argv, int *arg_ptr) Index: findutils-4.2.28/find/pred.c =================================================================== --- findutils-4.2.28.orig/find/pred.c 2006-11-09 00:40:54.102242213 -0800 +++ findutils-4.2.28/find/pred.c 2006-11-11 16:39:25.110381238 -0800 @@ -37,6 +37,7 @@ #include "printquoted.h" #include "buildcmd.h" #include "yesno.h" +#include #if ENABLE_NLS # include @@ -209,6 +210,7 @@ {pred_regex, "regex "}, {pred_samefile,"samefile "}, {pred_size, "size "}, + {pred_sparse, "sparse "}, {pred_true, "true "}, {pred_type, "type "}, {pred_uid, "uid "}, @@ -1346,6 +1348,28 @@ } boolean +pred_sparse (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) +{ + static dev_t cur_fs_dev = -1; + static struct statvfs cur_fs; + + (void) pathname; + (void) pred_ptr; + + if (!S_ISREG (stat_buf->st_mode)) + return false; + + if (stat_buf->st_dev != cur_fs_dev) { + if (statvfs(state.rel_pathname, &cur_fs)) { + return false; + } + cur_fs_dev = stat_buf->st_dev; + } + + return (stat_buf->st_size > stat_buf->st_blocks * cur_fs.f_bsize); +} + +boolean pred_samefile (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { /* Potential optimisation: because of the loop protection, we always Index: findutils-4.2.28/find/defs.h =================================================================== --- findutils-4.2.28.orig/find/defs.h 2006-11-09 00:53:11.220756091 -0800 +++ findutils-4.2.28/find/defs.h 2006-11-09 00:53:23.960817841 -0800 @@ -475,6 +475,7 @@ boolean pred_regex PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_samefile PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_size PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); +boolean pred_sparse PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_true PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_type PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_uid PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); Index: findutils-4.2.28/doc/find.texi =================================================================== --- findutils-4.2.28.orig/doc/find.texi 2006-11-09 00:55:49.291147085 -0800 +++ findutils-4.2.28/doc/find.texi 2006-11-09 01:05:32.961133296 -0800 @@ -919,6 +919,12 @@ (@pxref{Single File}). @end deffn +@deffn Test -sparse +True if the file is a regular file and has a size larger than the +number of blocks allocated multiplied by the blocksize. This generally +occurs if the file is sparse. +@end deffn + @node Type @section Type Index: findutils-4.2.28/find/find.1 =================================================================== --- findutils-4.2.28.orig/find/find.1 2006-11-09 00:55:49.103087138 -0800 +++ findutils-4.2.28/find/find.1 2006-11-09 00:59:57.978406247 -0800 @@ -429,6 +429,10 @@ differently. The `b' suffix always denotes 512-byte blocks and never 1 Kilobyte blocks, which is different to the behaviour of \-ls. +.IP \-sparse +True if the file is a regular file and has a size larger than the +number of blocks allocated multiplied by the blocksize. This generally +occurs if the file is sparse. .IP \-true Always true. .IP "\-type \fIc\fR" Index: findutils-4.2.28/find/testsuite/find.gnu/sparse.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ findutils-4.2.28/find/testsuite/find.gnu/sparse.exp 2006-11-09 01:16:23.428270215 -0800 @@ -0,0 +1,9 @@ +# tests for -sparse +exec rm -rf tmp +exec mkdir tmp +exec echo hi > tmp/notsparse +# note that some filesystems (such as XFS) won't create a sparse file when the +# "holes" are too small. hopefully this hole is large enough. +exec dd if=/dev/zero of=tmp/sparse seek=10000 bs=4096 count=1 2>/dev/null +find_start p { tmp -sparse } +exec rm -rf tmp Index: findutils-4.2.28/find/testsuite/find.gnu/sparse.xo =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ findutils-4.2.28/find/testsuite/find.gnu/sparse.xo 2006-11-09 01:03:14.172919476 -0800 @@ -0,0 +1 @@ +tmp/sparse