Monday, December 19, 2011

Checking that you can write to the destination path

Many times you will want to write to a folder on the drive, but how will you make sure the destination path you have is valid?

You can approach this problem in two ways:

  1. Prevent the user from entering an invalid path
  2. Validate the given path is valid
The first method is usually very easy to implement - the operating system provides the "file/folder open dialog". Just pop up the dialog and force the user the select an existing path.

But what if you can't use the file/folder open dialog? This can happen if the user needs to type in the path or you don't want to ask him (like in a configuration file).

In this case you will need to check the path is valid and make sure it is writable, but why check the path ourselves? Who are we to decide if the OS can accept the path or not? We'll just let the OS try to create the path and return the result.

First we'd like to make sure we can work with the path. The original path might contain environment path (e.g. %temp%), so we have to expand it first.
For this we will use ExpandEnvironmentStrings which expends any environment paths into it's full path (e.g. %windir% is expended to c:\windows), like so:
::ExpandEnvironmentStrings(lpTargetFolder, szPathExpended, MAX_PATH);
Now we have to create the entire folder structure to our path. We can use SHCreateDirectoryEx but I'm didn't like it because it doesn't handle relative paths and I found it failed on too many occasions. If you're path is simple and constant you should definitely use it. I prefer to use CreateDirectory which only creates the last folder in the path.
This simple code snippet will act the same as SHCreateDirectoryEx with less chance of failure (BTW, I'm using Unicode so I prefix the L char in front of my strings):
for (int i=0; i<iStringLen; i++)
      {
            if ((szPathExpended[i] == L'\\')) //are we at a folder
            {
                  szPathExpended[i] = 0; //ignore the rest of the path

                  if (GetFileAttributes(szPathExpended) == INVALID_FILE_ATTRIBUTES) //if the folder doesn't exist
                  {                            
                        if (!CreateDirectory(szPathExpended, NULL)) //iResult != ERROR_SUCCESS
                        {
                              bResultFlag = false;
                              break;
                        }
                  }

                  szPathExpended[i] = L'\\'; //continue to the next folder in the string
            }
      }

This creates the path up to the last \\. If we want to create a directory we will call CreateDirectory one more time, and if want to create a file we'll call the CreateFile function.


No comments:

Post a Comment