1

Under Linux, my program would do something like this:

  • Process 1 opens a file (e.g. by mapping it into memory). Let's call this file#1
  • Process 2 unlinks the file, and creates a new file with the same name. Let's call this file#2.
  • Process 1 continues to work with file#1. When it is closed, it is deleted (since it has no links). Process 1 continues to work with the content in file#1, and does not see content from file#2.
  • When both processes have exited, file#2 remains on disk.

I want to achieve the same semantics in Windows. After reading this question, I think FILE_SHARE_DELETE does basically this. Is opening the file with FILE_SHARE_DELETE enough, or do I need to consider something more?

The above execution flow is just an example, I know there are other ways of solving that exact problem in Windows, but I want to understand how to make such code portable between Windows and Linux.

Edit: to clarify: The use cases would be to reuse a filename for different unrelated files, but let existing processes keep their data (think transactional update of a config file for example), and to make a file anonymous (unnamed), but continue to use it like an anonymous memory map. Again I know both are possible on Windows through other means, but I am trying to find a way that is portable across platforms.

Community
  • 1
  • 1
Krumelur
  • 31,081
  • 7
  • 77
  • 119
  • No, that isn't what `FILE_SHARE_DELETE` does. The file won't be deleted until process 1 closes it, so process 2 will not be able to create a new file with the same name. – Harry Johnston Mar 31 '15 at 23:09
  • The second process should be able to rename the file, *then* delete it, then create a new file with the same name. (I'm a bit fuzzy on the rules governing when you can or can't rename a file that is in use. But I think it will work.) – Harry Johnston Mar 31 '15 at 23:14
  • I don't understand your first use case: your example contradicts your description, since different versions of a config file are not unrelated. (If the files really are unrelated, the proper - and portable! - solution is for the files to have unique names.) Your second use case as described is definitely not possible on Windows, since there is no such thing as an unnamed file. – Harry Johnston Apr 03 '15 at 00:53
  • I don't think there is any single portable approach that is ideal for all possible use cases. But if you use `FILE_SHARE_DELETE` and replace "delete" with "rename and then delete" it should work acceptably well for most purposes. (You can of course move the file as well as renaming it, to cover use cases where the user may be looking at the original directory and might become confused or annoyed by the temporary files.) – Harry Johnston Apr 03 '15 at 01:01
  • I meant that the file content is unrelated. The file name would have a special meaning in that case. I think you are right that I would also need to rename the file. This is exactly the kind of gotchas I am trying to find. – Krumelur Apr 04 '15 at 06:24
  • Oh, you just mean that the file contents written by one program doesn't depend on the file contents written by the other one? – Harry Johnston Apr 04 '15 at 09:37
  • Exactly. Think of it as transactional, snapshotted update of a file. The process will continue to "see" the file as it were when it first opened the handle. The path of the file would be used as a kind of contract in this case. I tried to rephrase the example. – Krumelur Apr 04 '15 at 10:53

1 Answers1

1

You can achieve this by using a combination of CreateFile, CreateFileMapping and MapViewOfFile calls. MapViewOfFile will give you a memory-mapped buffer of the file backed by the file on disk.

Following code when executed from different processes, will write the process id of last closing process in the file at c:\temp\temp.txt

int main()
{
 TCHAR szMsg[256];
 HANDLE hMapFile;
 LPCTSTR pBuf;

 HANDLE hFile = CreateFileW(
  L"C:\\Temp\\temp.txt", 
  GENERIC_WRITE|GENERIC_READ, 
  FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, 
  NULL, 
  CREATE_ALWAYS, 
  FILE_ATTRIBUTE_NORMAL,NULL);


 hMapFile = CreateFileMapping(
  hFile,      // Handle of file opened with rw access
  NULL,                    // default security
  PAGE_READWRITE,          // read/write access
  0,                       // maximum object size (high-order DWORD)
  BUF_SIZE,                // maximum object size (low-order DWORD)
  szName);                 // name of mapping object

 if (hMapFile == NULL)
 {
  printf( "Could not create file mapping object (%d).\n", GetLastError());
  return 1;
 }
 pBuf = (LPTSTR) MapViewOfFile(hMapFile,   // handle to map object
  FILE_MAP_ALL_ACCESS, // read/write permission
  0,
  0,
  BUF_SIZE);

 if (pBuf == NULL)
 {
  printf("Could not map view of file (%d).\n", GetLastError());
  CloseHandle(hMapFile);
  return 1;
 }
 
 wsprintfW(szMsg, L"This is process id %d", GetCurrentProcessId());
 CopyMemory((PVOID)pBuf, szMsg, (wcslen(szMsg) * sizeof(TCHAR)));

 MessageBoxW(NULL, szMsg, L"Check", MB_OK);

 UnmapViewOfFile(pBuf);
 CloseHandle(hMapFile);
 CloseHandle(hFile);
 return 0;


}

Make sure you open the file with GENERIC_READ|GENERIC_WRITE access and allow FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE access to subsequent opens.

Also note the use of CREATE_ALWAYS in CreateFile which will delete the old file and open a new one every-time CreateFile is called. This is the 'unlink' effect you talk about.

Code inspired from Creating Named Shared Memory at msdn.

  • Thanks! Is there a specific reason that memory mapping is used, or would normal stream I/O work as well? Note that I am not after sharing memory or data. – Krumelur Mar 31 '15 at 14:57
  • That won't work. On the second run, CreateFile will fail because it cannot create a new file with the same name as the existing one. – Harry Johnston Mar 31 '15 at 23:11
  • @Krumelur, memory mapping is used to avoid doing stream I/O on a file that might change on disk. Windows provides Memory Mapped Files to let each process have its own perception of a file without worrying about what's on disk. – ExceptionalHandler Apr 01 '15 at 03:33
  • Also, When writes to a file are shared between threads or processes, you might read inconsistent data from the file. First line maybe from old version of file and second line maybe from a newer version... – ExceptionalHandler Apr 01 '15 at 03:40
  • @ExceptionalHandler Sharing data is not what I want, I'm looking for the Linux semantics, where the first file becomes unnamed (and will be deleted once it is closed). – Krumelur Apr 02 '15 at 10:45