this checks for some race conditions between the first filename-based stat() we did before dispatching to the (hopefully correct) file type backup handler and the (hopefully) fd-based fstat() we did in the handler. if there is a problematic difference (e.g. file type changed), we r
(st_old, st_curr)
| 231 | |
| 232 | |
| 233 | def stat_update_check(st_old, st_curr): |
| 234 | """ |
| 235 | this checks for some race conditions between the first filename-based stat() |
| 236 | we did before dispatching to the (hopefully correct) file type backup handler |
| 237 | and the (hopefully) fd-based fstat() we did in the handler. |
| 238 | |
| 239 | if there is a problematic difference (e.g. file type changed), we rather |
| 240 | skip the file than being tricked into a security problem. |
| 241 | |
| 242 | such races should only happen if: |
| 243 | - we are backing up a live filesystem (no snapshot, not inactive) |
| 244 | - if files change due to normal fs activity at an unfortunate time |
| 245 | - if somebody is doing an attack against us |
| 246 | """ |
| 247 | # assuming that a file type change implicates a different inode change AND that inode numbers |
| 248 | # are not duplicate in a short timeframe, this check is redundant and solved by the ino check: |
| 249 | if stat.S_IFMT(st_old.st_mode) != stat.S_IFMT(st_curr.st_mode): |
| 250 | # in this case, we dispatched to wrong handler - abort |
| 251 | raise BackupRaceConditionError("file type changed (race condition), skipping file") |
| 252 | if st_old.st_ino != st_curr.st_ino: |
| 253 | # in this case, the hard-links-related code in create_helper has the wrong inode - abort! |
| 254 | raise BackupRaceConditionError("file inode changed (race condition), skipping file") |
| 255 | # looks ok, we are still dealing with the same thing - return current stat: |
| 256 | return st_curr |
| 257 | |
| 258 | |
| 259 | @contextmanager |
no test coverage detected