views:

547

answers:

3

When I save a file on a USB within my delphi application, how can I make sure the file is really (permanently) saved on the USB, when "Safely Remove Hardware" is not performed (especially forgotten to use)?
Telling our customer to use the windows feature "Safely Remove Hardware" doesn't work.
Is there a windows API command to flush the buffer, so that all data are written to the USB drive permanently?

+2  A: 

whatever happens, you can unplug the device yourself, i mean programatically. then you will be completely sure they have removed the device properly.

have a look at the answers for this question: safe-remove-usb-drive-using-win32-api. especially this link to a msdn kb article given in the answer.

Adrien Plisson
But what if the user doesn't want to remove the USB drive?
simon
the user is already removing the usb drive, i don't think he needs it anymore. more seriously, if he was waiting longer to use the drive, the file would end up written to disk (the file is not hold on cache forever). (i am dealing everyday with this kind of customer, the simpler it is for them, the better it is for everyone. tell them they can't use the drive, that's simple; tell them they must go to "safely remove hardware", that's too much. i can bet our OP already has some code to automatically detect USB drive insertion and copying the needed file to a predetermined path)
Adrien Plisson
Adrien, we only know the user is removing the drive *sometimes*. We don't know that the user *always* removes the drive after saving. We also don't know whether the drive is being used for things other than this program.
Rob Kennedy
@rob: you are right, i was just making assumptions based on my own personal experience... my bad.
Adrien Plisson
+9  A: 

When you open the file, specify "write through" (FILE_FLAG_WRITE_THROUGH flag to CreateFile()). This will force the OS to write out the file directly. It may still be in the OS cache to speed up subsequent reads, but that's not a problem for you.

If you do want to flush file buffers, there's of course always FlushFileBuffers()

MSalters
When I use FlushFileBuffers(), can I be sure that the file is stored physically on the USB drive? So, it doesn't vanish, after "uncontrolled" unplug?
max
@max: Yes, as long as there's enough time between the call to FlushFileBuffers() and the removal for the physical write to occur. IOW, if you try and write a 2GB file to the USB disk, call FlushFileBuffers(), and then +instantly+ remove the drive, it can still fail to be completely written - there's just not enough time allowed to complete the actual write operation. You need to educate your users on how to safely remove the drive, or at least wait until your app tells them they can remove it; your app can figure out how long it needs to wait before giving them that OK.
Ken White
Ken, you make it sound like FlushFileBuffers will return before it has actually finished flushing the file buffers. Is that correct? If so, then *how* should the program figure out how long it needs to wait?
Rob Kennedy
+3  A: 

Here's a function I used to flush data to a USB drive before ejecting it programmatically. This clones functionality from Mark Russinovich's "Sync" utility. I've had no problems with this code and it has been running on a lot of systems for a couple of years.

The most relevant part of this code is the call to FlushFileBuffers.

function FlushToDisk(sDriveLetter: string): boolean;
var
  hDrive: THandle;
  S:      string;
  OSFlushed: boolean;
  bResult: boolean;
begin
  bResult := False;
  S := '\\.\' + sDriveLetter + ':';

  //NOTE: this may only work for the SYSTEM user  
  hDrive    := CreateFile(PAnsiChar(S), GENERIC_READ or
    GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
    OPEN_EXISTING, 0, 0);
  OSFlushed := FlushFileBuffers(hDrive);

  CloseHandle(hDrive);

  if OSFlushed then
  begin
    bResult := True;
  end;

  Result := bResult;
end;
Mick
That's to flush all open files on the volume. If Max is only concerned about the files his program is writing, and not with any other files the user might be writing to the drive through other means, then he can probably just flush the handles to his files instead of flushing the whole volume, and he therefore wouldn't need administrative privileges.
Rob Kennedy