|
@@ -5170,14 +5170,31 @@ next:
|
|
|
}
|
|
|
|
|
|
/* Reached end of directory/root. Bump pos past the last item. */
|
|
|
- if (key_type == BTRFS_DIR_INDEX_KEY)
|
|
|
- /*
|
|
|
- * 32-bit glibc will use getdents64, but then strtol -
|
|
|
- * so the last number we can serve is this.
|
|
|
- */
|
|
|
- ctx->pos = 0x7fffffff;
|
|
|
- else
|
|
|
- ctx->pos++;
|
|
|
+ ctx->pos++;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Stop new entries from being returned after we return the last
|
|
|
+ * entry.
|
|
|
+ *
|
|
|
+ * New directory entries are assigned a strictly increasing
|
|
|
+ * offset. This means that new entries created during readdir
|
|
|
+ * are *guaranteed* to be seen in the future by that readdir.
|
|
|
+ * This has broken buggy programs which operate on names as
|
|
|
+ * they're returned by readdir. Until we re-use freed offsets
|
|
|
+ * we have this hack to stop new entries from being returned
|
|
|
+ * under the assumption that they'll never reach this huge
|
|
|
+ * offset.
|
|
|
+ *
|
|
|
+ * This is being careful not to overflow 32bit loff_t unless the
|
|
|
+ * last entry requires it because doing so has broken 32bit apps
|
|
|
+ * in the past.
|
|
|
+ */
|
|
|
+ if (key_type == BTRFS_DIR_INDEX_KEY) {
|
|
|
+ if (ctx->pos >= INT_MAX)
|
|
|
+ ctx->pos = LLONG_MAX;
|
|
|
+ else
|
|
|
+ ctx->pos = INT_MAX;
|
|
|
+ }
|
|
|
nopos:
|
|
|
ret = 0;
|
|
|
err:
|