views:

1322

answers:

7

Hi

I would like to implement a very simple Virtual Filesystem (VFS) which supports some basic file system operation like fwrite, fopen, fput, etc. The VFS is an abstraction layer on top of some concrete OS, e.g. Windows, Linux etc. Assume now, that the fopen interface looks something like this

FILE VFS_File_Open( const unsigned char* strFile, int flags );

Now I am wondering how I can make in the actual implementation of this interface the distinction about which filesystem I am talking to. Is there in C something that tells me on which OS the application is running so that I could do something like this:

FILE VFS_File_Open( const unsigned char strFile, int flags )
{
int OS = getOSID();

if (0S == 1)
  //implement here the system calls required to open a file on a WIN OS
else if (OS == 2)
  //implement here the system calls required to open a file on a Linux OS
etc  
}

EDIT:

Thanks so far for your answer gents, that was really helpful to clarify some things!

Now I am wondering if anyone knows where I can find the system calls for file oeprations for windows? It is easy to find them for Linux but I struggeled to find something similar for windows, e.g. I would be interested in the system calls to open a file, write a file, etc.

On another note: The C stdio.h offers a number of stand IO operations like

FILE * fopen (const char *filename, const char *opentype)

In other words, I do not have to reimplement the fopen routine in my VFS as the Gnu C library takes care about what OS it is dealing with, is that right? I just have to implement functionaliy that is not supported by stdio library, e.g. creating directories, which differ from filesystem to filesystem?

Thanks

+10  A: 

Maybe the simplest/cleanest implementation would be to create two separate libraries, one for windows and one for linux, without littering your code with cascaded if and switch statements. The libraries would implement the same functions, defined in a common header.

Also, remember that the code inside your check OS == something would be compiled and linked on all systems, so e.g. the library compiled on linux should be able to resolve the windows system calls...

I think separating things (different OS, different cpp files) is the simplest solution.

EDIT:

If you are using C++, why not just relying on streams? The standard library already provides the functionality you are trying to implement and is available on all platforms.
Otherwise, here's a link to Windows File Management Functions.

SECOND EDIT:

If you want a cross-platform file system library, supporting among other things directory creation, you could check the boost filesystem library.

Paolo Tedesco
I like the idea with the common header and the different libraries for the differnt OSes. In essence, I have then just to do what Nick D. suggested and include the corresponding library depending on the OS.
Or rather, when you build a Windows solution you link the windows library and so on. You include the common header in both cases: compilation will be the same, platform-specific stuff will be taken into account in the linking phase.
Paolo Tedesco
+3  A: 

I don't think you can compile a module for different OSes, the way you want.

// Make the distinction at compile time,

FILE VFS_File_Open( const unsigned char strFile, int flags )
{
#ifdef _WINDOWS
    //implement here the system calls required to open a file on a WIN OS
#endif
#ifdef _LINUX
    //implement here the system calls required to open a file on a Linux OS
#endif
    etc
}
Nick D
Of course, if you want to keep everything in a single file, the distinction must be done at compile time (+1). I still think separating stuff is better.
Paolo Tedesco
Thank you very much. This was also one approach I was thinking of! So the combination with orsogufo answer should give me a good start!
yes, I agree. Actually that's a common *pattern* to design cross platform projects.
Nick D
+1  A: 

You could try PhysicsFS library.

HMage
A: 

Standard C has no such feature. Notice that the notion of "concrete OS" is also a bit vague: are Windows XP and Windows Vista the same "concrete OS", or different ones? Are CentOS and Ubuntu the same OS, or different ones?

Apparently, you are only looking for API differences, so in most cases, you can probably ignore version differences and distribution differences (although both Windows and Linux grow new system calls from time to time). In this case, it is best to preprocessor conditional compilation - since the code making Linux-specific calls won't even compile on Windows.

Traditionally, the system compilers have various macros predefined. Here are a few such macros, on respective systems: _WIN32, __linux, __linux__, __AIX__, __hpux, ... If you need to identify a specific system, you should ask again on SO.

Martin v. Löwis
+1  A: 

Actually implemented this, so from experience here:

The first thing to do is use classes. There is no fopen() equivalent. If there are flags, they're going to be an enum. Filenames are wchar_t nowadays.

The second thing to do is factor out the OS-dependent parts of your file class. They should be in separate methods. You move these to a seperate file. For every OS you have, there will be a different file implementing the same methods. When you link your app, you know the target architecture and you can pick the correct versions.

MSalters
A: 

I am just wondering if anyone knows where I can find the system calls for file oeprations for windows? It is easy to find them for Linux but I struggeled to find something simiar for windows, e.g. I would be interested in the system calls to open a file, write a file, etc

you should rather edit your question if you want to ask for something more, rather than posting your new question as an answer...
Paolo Tedesco
A: 

If you're looking for a way to abstract yourself from the properties of the filesystem you're using (path separators etc.), and if you're happy with a C++-only solution, take a look at Boost.Filesystem.

Paths can be specified in the portable generic path format (basically POSIX format) and are automatically converted to the native format:

path my_path( "some_dir/file.txt" );

Elements can be concatenated onto the path using the / operator, and the result can then directly be used to open a file:

ifstream file1( my_path / "foo/bar" );

What's more, this functionality is part of Technical Report 2, meaning that it will likely make its way into the standard library.

Martin B