}
run_test 56rd "check lfs find --printf special files"
+test_56re()
+{
+ local dir=$DIR/$tdir
+ local file=$dir/a
+ local test_cases=(
+ "|%5s|" "|%05s|" "|%0s|" "|%-5s|" "|%-0s|"
+ "|%5G|" "|%05G|" "|%0G|" "|%-5G|" "|%-0G|"
+ "|%25i|" "|%025i|" "|%0i|" "|%-25i|" "|%-0i|"
+ "|%5k|" "|%05k|" "|%0k|" "|%-5k|" "|%-0k|"
+ "|%5y|" "|%05y|" "|%0y|" "|%-5y|" "|%-0y|"
+ "|%5m|" "|%05m|" "|%0m|" "|%-5m|" "|%-0m|" "|%-05m|"
+ "|%----5s|" "|%----00005s|" "|%00005s|"
+ "|%020|" "|%20|" "|%-20|" "|%-020|" "|%---020|" "|%---20|"
+ )
+
+ test_mkdir "$dir"
+ touch "$file"
+ truncate -s 37 "$file"
+
+ for format in ${test_cases[@]}; do
+ local expected=$(find "$dir" -type f -printf "$format\n")
+ local output=$($LFS find "$dir" -type f -printf "$format\n")
+
+ [[ $output == $expected ]] ||
+ error "Unexpected output to \"$format\", expected '$expected' got '$output'"
+ done
+}
+run_test 56re "check lfs find -printf width format specifiers are consistant with regular find"
+
+test_56rf()
+{
+ local dir=$DIR/$tdir
+ local file=$dir/a
+ local test_cases
+ local poolname=testpool56rf
+ local stripe_count
+ local fid
+
+ test_mkdir "$dir"
+ pool_add $poolname || error "Could not create pool '$poolname'"
+
+ lfs setstripe -c 2 -S 4M -p $poolname "$file"
+ stripe_count=$(lfs getstripe -c "$file")
+ fid=$($LFS path2fid "$file" | sed 's/\[\(.*\)\]/\1/')
+ len=$((${#fid} + 5))
+
+ test_cases=(
+ "|%${len}LF|" "| $fid|"
+ "|%0${len}LF|" "| $fid|"
+ "|%0LF|" "|$fid|"
+ "|%-${len}LF|" "|$fid |"
+ "|%-0LF|" "|$fid|"
+
+ "|%14Lp|" "| $poolname|"
+ "|%014Lp|" "| $poolname|"
+ "|%0Lp|" "|$poolname|"
+ "|%-14Lp|" "|$poolname |"
+ "|%-0Lp|" "|$poolname|"
+ "|%07Lp|" "|$poolname|"
+ "|%-7Lp|" "|$poolname|"
+
+ "|%4Lc|" "| $stripe_count|"
+ "|%04Lc|" "| $stripe_count|"
+ "|%0Lc|" "|$stripe_count|"
+ "|%-4Lc|" "|$stripe_count |"
+ "|%-0Lc|" "|$stripe_count|"
+
+ "|%10LS|" "| 4194304|"
+ "|%010LS|" "| 4194304|"
+ "|%0LS|" "|4194304|"
+ "|%-10LS|" "|4194304 |"
+ "|%-0LS|" "|4194304|"
+ )
+
+ for (( i = 0; i < ${#test_cases[@]}; i += 2 )); do
+ local format=${test_cases[i]}
+ local expected=${test_cases[i + 1]}
+ local output=$($LFS find "$dir" -type f -printf "$format\n")
+
+ [[ $output == $expected ]] ||
+ error "Unexpected output to \"$format\", expected '$expected' got '$output'"
+ done
+}
+run_test 56rf "check lfs find -printf width format specifiers for lustre specific formats"
+
test_56s() { # LU-611 #LU-9369
[[ $OSTCOUNT -lt 2 ]] && skip_env "need at least 2 OSTs"
return snprintf(buffer, size, "%s", access_string);
}
+static int parse_format_width(char **seq, size_t buf_size, int *width,
+ char *padding)
+{
+ bool negative_width = false;
+ char *end = NULL;
+ int parsed = 0;
+
+ *padding = ' ';
+ *width = 0;
+
+ /* GNU find supports formats such as "%----10s" */
+ while (**seq == '-') {
+ (*seq)++;
+ parsed++;
+ negative_width = true;
+ }
+
+ /* GNU find and printf only do 0 padding on the left (width > 0)
+ * %-010m <=> %-10m.
+ */
+ if (**seq == '0' && !negative_width)
+ *padding = '0';
+
+ errno = 0;
+ *width = strtol(*seq, &end, 10);
+ if (errno != 0)
+ return -errno;
+ if (*width >= buf_size)
+ *width = buf_size - 1;
+
+ /* increase the number of processed characters */
+ parsed += end - *seq;
+ *seq = end;
+ if (negative_width)
+ *width = -*width;
+
+ /* GNU find only does 0 padding for %S, %d and %m. */
+ switch (**seq) {
+ case 'S':
+ case 'd':
+ case 'm':
+ break;
+ default:
+ *padding = ' ';
+ break;
+ }
+
+ return parsed;
+}
+
/*
* Interpret format specifiers beginning with '%'.
*
int *wrote, struct find_param *param,
char *path, __u32 projid, int d)
{
- __u16 mode = param->fp_lmd->lmd_stx.stx_mode;
uint64_t blocks = param->fp_lmd->lmd_stx.stx_blocks;
+ __u16 mode = param->fp_lmd->lmd_stx.stx_mode;
+ char padding;
+ int width_rc;
int rc = 1; /* most specifiers are single character */
+ int width;
*wrote = 0;
+ width_rc = parse_format_width(&seq, size, &width, &padding);
+ if (width_rc < 0)
+ return 0;
+
switch (*seq) {
case 'a': case 'A':
case 'c': case 'C':
}
case 'G': /* GID of owner */
*wrote = snprintf(buffer, size, "%u",
- param->fp_lmd->lmd_stx.stx_gid);
+ param->fp_lmd->lmd_stx.stx_gid);
break;
case 'i': /* inode number */
*wrote = snprintf(buffer, size, "%llu",
path, projid, d);
break;
case 'm': /* file mode in octal */
- *wrote = snprintf(buffer, size, "%#o", (mode & (~S_IFMT)));
+ *wrote = snprintf(buffer, size, "%o", (mode & (~S_IFMT)));
break;
case 'M': /* file access mode */
*wrote = snprintf_access_mode(buffer, size, mode);
break;
}
+ if (rc == 0)
+ /* if parsing failed, return 0 to avoid skipping width_rc */
+ return 0;
+
+ if (width > 0 && width > *wrote) {
+ /* left padding */
+ int shift = width - *wrote;
+
+ /* '\0' is added by caller if necessary */
+ memmove(buffer + shift, buffer, *wrote);
+ memset(buffer, padding, shift);
+ *wrote += shift;
+ } else if (width < 0 && -width > *wrote) {
+ /* right padding */
+ int shift = -width - *wrote;
+
+ memset(buffer + *wrote, padding, shift);
+ *wrote += shift;
+ }
+
if (*wrote >= size)
/* output of snprintf was truncated */
*wrote = size - 1;
- return rc;
+ return width_rc + rc;
}
/*
rc = printf_format_directive(fmt_char + 1, buff,
buff_size, &written, param,
path, projid, d);
- } else if (*fmt_char == '\\')
+ } else if (*fmt_char == '\\') {
rc = printf_format_escape(fmt_char + 1, buff,
buff_size, &written);
+ }
if (rc > 0) {
/* Either a '\' escape or '%' format was processed.
fmt_char += (rc + 1);
buff += written;
buff_size -= written;
+ } else if (rc < 0) {
+ return;
} else {
/* Regular char or invalid escape/format.
* Either way, copy current character.
return 0;
}
+ /* GNU find supports formats such as "%----10s" */
+ while (curr == '-')
+ curr = *(++c);
+
+ if (isdigit(curr)) {
+ /* skip width format specifier */
+ while (isdigit(*c))
+ c++;
+ }
+
+ curr = *c;
next = *(c + 1);
+
if ((next == '\0') || (next == '%') || (next == '\\'))
/* Treat as single char format directive */
goto check_single;