Thanks for looking at this — the confusion is understandable, and I think it comes down to one specific point about short-circuit evaluation, so let me isolate it precisely.
You're right that && short-circuits: when the left operand is false, the right operand is never evaluated.
But that's not the situation here. In our case, S_ISBLK(statbuf.st_mode) is true — the source really is a block device (a real partition node).
Short-circuiting only skips evaluation when the left side is false; when the left side is true, C is required to evaluate the right side too, and the result of the whole && expression is simply whatever that right side evaluates to.
So walking through it concretely with S_ISBLK == true:
The ioctl() call does run (it's not skipped — the left side was true), and it does succeed, writing the correct size into size as a side effect.
But the comparison 0 < 0 is false, so the whole && expression is false — not because S_ISBLK failed, but because the ioctl succeeded.
The branch condition was deliberately written to only be true when the ioctl fails, so a successful ioctl makes the branch condition false and the code falls through to the trailing else, which unconditionally sets size = -1 and discarding the value the ioctl just correctly wrote.
So the one place that would keep a successful detection is unreachable — every successful ioctl call on a block device source falls straight through to the generic else { size = -1; }.
The fix simply separates "is this a block device" from "did the ioctl on it fail", so a successful call is no longer bound to a condition that requires failure to be true:
else if (S_ISBLK(statbuf.st_mode)) {
if (ioctl(fdin, BLKGETSIZE64, &size) < 0) {
ERROR("Cannot get size of Block Device %s", path);
size = -1;
}
/* else: size already holds the correct value from ioctl() */
}...
Happy to resend the patch with a clearer commit message if that would help reviewers avoid the same misreading — let me know.
Best regards,
Dit