# Buggy code
def wipe_path(pathname, idle=False):
    """Wipe the free space in the path
    This function uses an iterator to update the GUI."""

    def temporaryfile():
        # reference
        # http://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits
        maxlen = 185
        f = None
        while True:
            try:
                f = tempfile.NamedTemporaryFile(
                    dir=pathname, suffix=__random_string(maxlen), delete=False
                )
                # In case the application closes prematurely, make sure this
                # file is deleted
                atexit.register(delete, f.name, allow_shred=False, ignore_missing=True)
                break
            except OSError as e:
                if e.errno in (
                    errno.ENAMETOOLONG,
                    errno.ENOSPC,
                    errno.ENOENT,
                    errno.EINVAL,
                ):
                    # ext3 on Linux 3.5 returns ENOSPC if the full path is greater than 264.
                    # Shrinking the size helps.

                    # Microsoft Windows returns ENOENT "No such file or directory"
                    # or EINVAL "Invalid argument"
                    # when the path is too long such as %TEMP% but not in C:\
                    if maxlen > 5:
                        maxlen -= 5
                        continue
                raise
        return f

    def estimate_completion():
        """Return (percent, seconds) to complete"""
        remaining_bytes = free_space(pathname)
        done_bytes = start_free_bytes - remaining_bytes
        if done_bytes < 0:
            # maybe user deleted large file after starting wipe
            done_bytes = 0
        if 0 == start_free_bytes:
            done_percent = 0
        else:
            done_percent = 1.0 * done_bytes / (start_free_bytes + 1)
        done_time = time.time() - start_time
        rate = done_bytes / (done_time + 0.0001)  # bytes per second
        remaining_seconds = int(remaining_bytes / (rate + 0.0001))
        return 1, done_percent, remaining_seconds

    logger.debug(_("Wiping path: %s") % pathname)
    files = []
    total_bytes = 0
    start_free_bytes = free_space(pathname)
    start_time = time.time()
    # Because FAT32 has a maximum file size of 4,294,967,295 bytes,
    # this loop is sometimes necessary to create multiple files.
    while True:
        try:
            logger.debug(_("Creating new, temporary file for wiping free space."))
            f = temporaryfile()
        except OSError as e:
            # Linux gives errno 24
            # Windows gives errno 28 No space left on device
            if e.errno in (errno.EMFILE, errno.ENOSPC):
                break
            else:
                raise
        last_idle = time.time()
        # Write large blocks to quickly fill the disk.
        blanks = b"\0" * 65536
        while True:
            try:
                f.write(blanks)
            except IOError as e:
                if e.errno == errno.ENOSPC:
                    if len(blanks) > 1:
                        # Try writing smaller blocks
                        blanks = blanks[0 : len(blanks) // 2]
                    else:
                        break
                elif e.errno == errno.EFBIG:
                    break
                else:
                    raise
            if idle and (time.time() - last_idle) > 2:
                # Keep the GUI responding, and allow the user to abort.
                # Also display the ETA.
                yield estimate_completion()
                last_idle = time.time()
        # Write to OS buffer
        try:
            f.flush()
        except IOError as e:
            # IOError: [Errno 28] No space left on device
            # seen on Microsoft Windows XP SP3 with ~30GB free space but
            # not on another XP SP3 with 64MB free space
            if not e.errno == errno.ENOSPC:
                logger.error(_("Error #%d when flushing the file buffer." % e.errno))

        os.fsync(f.fileno())  # write to disk
        # Remember to delete
        files.append(f)
        # For statistics
        total_bytes += f.tell()
        # If no bytes were written, then quit.
        # See https://github.com/bleachbit/bleachbit/issues/502
        if (
            start_free_bytes - total_bytes < 2
        ):  # Modified by Marvin to fix the issue #1051 [12/06/2020]
            break
    # sync to disk
    sync()
    # statistics
    elapsed_sec = time.time() - start_time
    rate_mbs = (total_bytes / (1000 * 1000)) / elapsed_sec
    logger.info(
        _(
            "Wrote {files:,} files and {bytes:,} bytes in {seconds:,} seconds at {rate:.2f} MB/s"
        ).format(
            files=len(files), bytes=total_bytes, seconds=int(elapsed_sec), rate=rate_mbs
        )
    )
    # how much free space is left (should be near zero)
    if "posix" == os.name:
        stats = os.statvfs(pathname)
        logger.info(
            _(
                "{bytes:,} bytes and {inodes:,} inodes available to non-super-user"
            ).format(bytes=stats.f_bsize * stats.f_bavail, inodes=stats.f_favail)
        )
        logger.info(
            _("{bytes:,} bytes and {inodes:,} inodes available to super-user").format(
                bytes=stats.f_bsize * stats.f_bfree, inodes=stats.f_ffree
            )
        )
    # truncate and close files
    for f in files:
        truncate_f(f)

        while True:
            try:
                # Nikita: I noticed a bug that prevented file handles from
                # being closed on FAT32. It sometimes takes two .close() calls
                # to do actually close (and therefore delete) a temporary file
                f.close()
                break
            except IOError as e:
                if e.errno == 0:
                    logger.debug(_("Handled unknown error #0 while truncating file."))
                    time.sleep(0.1)
        # explicitly delete
        delete(f.name, ignore_missing=True)


# Traceback (OSError)
dzmitry@dzmitry-Satellite-C50-A-L6K:~/Downloads/bleachbit-master$ sudo python3 bleachbit.py
clean_operation('_gui'), options = '[]'
Wiping path: /media/dzmitry/6A17-921B
Creating new, temporary file for wiping free space.
Error #27 when flushing the file buffer.
Creating new, temporary file for wiping free space.
Wrote 2 files and 8,024,788,992 bytes in 892 seconds at 9.00 MB/s
0 bytes and 0 inodes available to non-super-user
0 bytes and 0 inodes available to super-user
Error: _gui.free_disk_space: Function: Overwrite free disk space /media/dzmitry/6A17-921B
Traceback (most recent call last):
File "/home/dzmitry/Downloads/bleachbit-master/bleachbit/Worker.py", line 87, in execute
for ret in cmd.execute(self.really_delete):
File "/home/dzmitry/Downloads/bleachbit-master/bleachbit/Command.py", line 145, in execute
for func_ret in self.func():
File "/home/dzmitry/Downloads/bleachbit-master/bleachbit/Cleaner.py", line 743, in wipe_path_func
for ret in FileUtilities.wipe_path(path, idle=True):
File "/home/dzmitry/Downloads/bleachbit-master/bleachbit/FileUtilities.py", line 984, in wipe_path
truncate_f(f)
File "/home/dzmitry/Downloads/bleachbit-master/bleachbit/FileUtilities.py", line 680, in truncate_f
f.truncate(0)
File "/usr/lib/python3.5/tempfile.py", line 622, in func_wrapper
return func(*args, **kwargs)
OSError: [Errno 27] File too large
Exception ignored in: <bound method _TemporaryFileCloser.__del__ of <tempfile._TemporaryFileCloser object at 0x7fdac08e44a8>>
Traceback (most recent call last):
File "/usr/lib/python3.5/tempfile.py", line 589, in __del__
self.close()
File "/usr/lib/python3.5/tempfile.py", line 582, in close
self.file.close()
OSError: [Errno 28] No space left on device
Exception ignored in: <bound method _TemporaryFileCloser.__del__ of <tempfile._TemporaryFileCloser object at 0x7fdab9fb7ac8>>
Traceback (most recent call last):
File "/usr/lib/python3.5/tempfile.py", line 589, in __del__
self.close()
File "/usr/lib/python3.5/tempfile.py", line 582, in close
self.file.close()
OSError: [Errno 27] File too large
elapsed time: 892 seconds

# Fixed code
def wipe_path(pathname, idle=False):
    """Wipe the free space in the path
    This function uses an iterator to update the GUI."""

    def temporaryfile():
        # reference
        # http://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits
        maxlen = 185
        f = None
        while True:
            try:
                f = tempfile.NamedTemporaryFile(
                    dir=pathname, suffix=__random_string(maxlen), delete=False
                )
                # In case the application closes prematurely, make sure this
                # file is deleted
                atexit.register(delete, f.name, allow_shred=False, ignore_missing=True)
                break
            except OSError as e:
                if e.errno in (
                    errno.ENAMETOOLONG,
                    errno.ENOSPC,
                    errno.ENOENT,
                    errno.EINVAL,
                ):
                    # ext3 on Linux 3.5 returns ENOSPC if the full path is greater than 264.
                    # Shrinking the size helps.

                    # Microsoft Windows returns ENOENT "No such file or directory"
                    # or EINVAL "Invalid argument"
                    # when the path is too long such as %TEMP% but not in C:\
                    if maxlen > 5:
                        maxlen -= 5
                        continue
                raise
        return f

    def estimate_completion():
        """Return (percent, seconds) to complete"""
        remaining_bytes = free_space(pathname)
        done_bytes = start_free_bytes - remaining_bytes
        if done_bytes < 0:
            # maybe user deleted large file after starting wipe
            done_bytes = 0
        if 0 == start_free_bytes:
            done_percent = 0
        else:
            done_percent = 1.0 * done_bytes / (start_free_bytes + 1)
        done_time = time.time() - start_time
        rate = done_bytes / (done_time + 0.0001)  # bytes per second
        remaining_seconds = int(remaining_bytes / (rate + 0.0001))
        return 1, done_percent, remaining_seconds

    logger.debug(_("Wiping path: %s") % pathname)
    files = []
    total_bytes = 0
    start_free_bytes = free_space(pathname)
    start_time = time.time()
    # Because FAT32 has a maximum file size of 4,294,967,295 bytes,
    # this loop is sometimes necessary to create multiple files.
    while True:
        try:
            logger.debug(_("Creating new, temporary file for wiping free space."))
            f = temporaryfile()
        except OSError as e:
            # Linux gives errno 24
            # Windows gives errno 28 No space left on device
            if e.errno in (errno.EMFILE, errno.ENOSPC):
                break
            else:
                raise

        # Get the file system type from the given path
        fstype = get_filesystem_type(pathname)
        fstype = fstype[0]
        print("File System:" + fstype)
        # print(f.name) # Added by Marvin for debugging #issue 1051
        last_idle = time.time()
        # Write large blocks to quickly fill the disk.
        blanks = b"\0" * 65536
        writtensize = 0

        while True:
            try:
                if fstype != "vfat":
                    f.write(blanks)
                elif writtensize < 4 * 1024 * 1024 * 1024 - 65536:
                    writtensize += f.write(blanks)
                else:
                    break

            except IOError as e:
                if e.errno == errno.ENOSPC:
                    if len(blanks) > 1:
                        # Try writing smaller blocks
                        blanks = blanks[0 : len(blanks) // 2]
                    else:
                        break
                elif e.errno == errno.EFBIG:
                    break
                else:
                    raise
            if idle and (time.time() - last_idle) > 2:
                # Keep the GUI responding, and allow the user to abort.
                # Also display the ETA.
                yield estimate_completion()
                last_idle = time.time()
        # Write to OS buffer
        try:
            f.flush()
        except IOError as e:
            # IOError: [Errno 28] No space left on device
            # seen on Microsoft Windows XP SP3 with ~30GB free space but
            # not on another XP SP3 with 64MB free space
            if not e.errno == errno.ENOSPC:
                logger.error(_("Error #%d when flushing the file buffer." % e.errno))

        os.fsync(f.fileno())  # write to disk
        # Remember to delete
        files.append(f)
        # For statistics
        total_bytes += f.tell()
        # If no bytes were written, then quit.
        # See https://github.com/bleachbit/bleachbit/issues/502
        if (
            start_free_bytes - total_bytes < 2
        ):  # Modified by Marvin to fix the issue #1051 [12/06/2020]
            break
    # sync to disk
    sync()
    # statistics
    elapsed_sec = time.time() - start_time
    rate_mbs = (total_bytes / (1000 * 1000)) / elapsed_sec
    logger.info(
        _(
            "Wrote {files:,} files and {bytes:,} bytes in {seconds:,} seconds at {rate:.2f} MB/s"
        ).format(
            files=len(files), bytes=total_bytes, seconds=int(elapsed_sec), rate=rate_mbs
        )
    )
    # how much free space is left (should be near zero)
    if "posix" == os.name:
        stats = os.statvfs(pathname)
        logger.info(
            _(
                "{bytes:,} bytes and {inodes:,} inodes available to non-super-user"
            ).format(bytes=stats.f_bsize * stats.f_bavail, inodes=stats.f_favail)
        )
        logger.info(
            _("{bytes:,} bytes and {inodes:,} inodes available to super-user").format(
                bytes=stats.f_bsize * stats.f_bfree, inodes=stats.f_ffree
            )
        )
    # truncate and close files
    for f in files:
        truncate_f(f)

        while True:
            try:
                # Nikita: I noticed a bug that prevented file handles from
                # being closed on FAT32. It sometimes takes two .close() calls
                # to do actually close (and therefore delete) a temporary file
                f.close()
                break
            except IOError as e:
                if e.errno == 0:
                    logger.debug(_("Handled unknown error #0 while truncating file."))
                    time.sleep(0.1)
        # explicitly delete
        delete(f.name, ignore_missing=True)