Windows up one directory from current path - c++

I have been searching for hours but cant find a solution to this as yet. Apologies it is probably really simple.
My program is using CreateDirectory to create a new directory and then set the path to it to receive a number of data files:
if (CreateDirectory(dateTime.c_str(), NULL) || ERROR_ALREADY_EXISTS == GetLastError())
{
SetCurrentDirectory(dateTime.c_str());
}
Once all the data files have been generated I would like to move back up one directory without specifying the absolute path. Something equivalent to cd.. or ../ Does anyone know the best way to do this?

One possible approach is to get the current directory (GetCurrentDirectory) before changing to a new one and once complete, then change back the desired directory; akin to a push/pop.
In the sample I've left out error checking and buffer size requirements for simplicity.
TCHAR resetDir[1024] = {};
GetCurrentDirectory(1024, resetDir);
//... Do some work, change directories etc...
// Reset the directory
SetCurrentDirectory(resetDir);
Side note: the current directory when the process is launched is not necessarily the same as the directory the process image is in (the exe path).
Relative changes can be done with a simple
SetCurrentDirectory(_T(".."));
Although basing the relative from the current directory would also work (and may be preferable);
SetCurrentDirectory((currentDir + _T("\\..")).c_str());

Internally, cd command ends using SetCurrentDirectory. So to get something equivalent to cd.. or cd ../ you can simply use:
cr = ::SetCurrentDirectory("..");
cr should be non zero if it succeded and 0 if it failed. In the latter case use GetLastError to get further information.

Related

How to perform a quick check if the file directory for a script in matlab is correct?

I have a script which relies on different files located in specific folders which are important to run the script without errors. In order to define the path location I decided to create many variables with the according path location name as string:
file directory var file directory location % default entries which
% only work with my computer
fd_1 = '\C:\Testrun\pathfinder.xls\';
fd_2 = '\C:\Testrun\pathfilter.slx\';
fd_3 = '\C:\Testrun\splinegenerator.xls\';
fd_4 = '\C:\Testrun\loftcreator.xls\';
fd_5 = '\C:\Testrun\surface_to_volume.xls\';
fd_6 = '\C:\Testrun\stp_creator.xls\';
fd_7 = '\C:\Testrun\CAD_file.stp\';
fd_8 = '\C:\Testrun\CAD_support_1.atm\';
fd_9 = '\C:\Testrun\CAD_support_2.atm\';
fd_10 = '\C:\Testrun\CAD_support_3.atm\';
This allowed me to use my script on my computer. However this was a pretty static solution which only works for one pc. Hence I need the following dynmamic routine to be coded:
0.) I created a while loop in order to rerun my script with the switch case/expression:
<<<here is the missing code for the file directory check>>>
%(I wanted to use the "strcmp" command to compare the strings with each other?)
<<<Here is my code with the specific while loop to rerun it>>>
1.) Before I enter this loop need to perform a quick check, if the files are correctly located.
2.) If the file directory cannot be assigned to the specific variables responsible for the file
directory name (e.g directory could not be found), a new file directory will be choosen by the
user
3.) The newly choosen file directory will be stored with the default file directory in a list
4.) The variable responsible for the file directory changes according to the list index which the
user choose from the list of stored file directory names
5.) The selection of the specific list index as well as the changes in the list will be permenantly
stored (The changes in the list should be saved and recalled again in the script upon rerunning
or exiting/reopening the script)
6.) The list index can be deleted if the user is unsatisfied with the file directory (e.g due the
file directory corruption)
Is it possible to write such a code and how would it be structered?
I think to put all those folders and files in the same path of main program, by this way, no need to mention drive letter like c:\ or d:, just mentiob folder name and its subfolders, and you can copy the main folder and run your program in another computer without changing anything, just run the main program.

Directory navigation in OPEN clause

How can I read from a parent directory using the OPEN clause? Let's say
OPEN (11,file='../inf/input.dat',form='formatted',status='old')
, which doesn't work. I get:
forrtl: severe (29): file not found, unit 11, file /home/cg/compile/comp/../inf/input.dat
I would like to read from the parent directory just before inf. Is that possible?
Unfortunately there is no unique way to do this, since paths are OS dependent. In order to this in a robust way you might need to define a function that look for the OS while preprocessing (cf. compilation flags e.g. here).
For *nix systems (Unix, including OSX, and Linux) the option you provided should suffice
../
in the path goes to the previous directory.
However in windows there is no way that I know to go in the above directory (I don't have a Windows system with me at the moment).
However you can workaround this limitation with the GetModuleFileName API function. (note that this will not work in the systems above)
CHARACTER*(*) pathname ! full name
INTEGER L ! length
L= GetModuleFileName(NULL,pathname,LEN(pathname))
Fullname will now contain the full path where you run your program, so you can do all sort of string operation you want.
If you want to go above one level
Idx = index(trim(pathname), '/', .True.)
Finds the index of the last '/' character in the pathname (you might need to look for the one before the last).
outfile_path=pathname(:idx)+'/inf/input.dat'
will be now the path you want.

Diagnosing QDir::rmdir failure

I’m using the following code to delete an empty folder on Linux:
bool removeFolder (const QString& path)
{
QDir dir(path);
assert(dir.exists());
return dir.rmdir(".");
}
For some reason it sometimes returns false (for specific folders, but those folders don’t seem to be wrong in any way). If I subsequently use ::rmdir from <unistd.h> to remove the same folder, it succeeds.
How can I tell why QDir::rmdir is failing?
This never happened on Windows so far, QDir::rmdir just works.
Confirming: works on windown, fails on linux.
Reading the "rmdir" doc in <unistd>, here https://pubs.opengroup.org/onlinepubs/007904875/functions/rmdir.html, it says there that "If the path argument refers to a path whose final component is either dot or dot-dot, rmdir() shall fail." So what's probably happening is that QDir::rmdir() is calling the unistd rmdir() function in linux, and this one fails with ".".
I tried to just use the full absolute path ( QDir::rmdir(absolutePath) ) and it worked; however, i see basically no point in using QDir::rmdir() over unistd's rmdir(), so i''ll stick w/ the unistd rmdir() from now on.
note: QDir::removeRecursively() is a different story: it seems to work okay, and it's way more convenient than going through opendir() and then successive readdir()'s (or the nftw(...FTW_DEPTH...) thingie).
I had the same problem but on Windows, I could not delete an empty directory with QDir().rmdir(path);. This happened on some older hard drive so may be the ancient file system was to blame. But I found a hack:
QFile(path).setPermissions(QFile::WriteOther); // this works even for dirs
bool success = QDir().rmdir(path);
Of course, you should revert the permissions back to original values if the deletion was unsuccessful anyway, but that's a different story.
Try to use this one:
dir.rmdir(dir.absolutePath())

Get proper case working directory?

To better familiarize myself with C++, I'm redoing an old college OS assignment: program your own shell. I'm using all sorts of Windows.h that I've never known existed. So far I've made good progress but I've noticed something about my cd implementation and my working directory I get back from getcwd.
My cd command does some error checking but ultimately it comes down to chdir(path). Say I'm at C:\ and there exists a folder FOLDER. If I use chdir("folder") then later when I call getcwd(dir, FILENAME_MAX) then I'll get the string C:\folder instead of the case correct string C:\FOLDER. How can I retrieve the working directory with every folder having the proper case?
Note: When I first start my shell and run my pwd command (that solely prints dir from my getcwd call), I get a path that is properly cased. As soon as I start changing the working directory then the casing always matches my strings instead of the actual folder casing.
I think the Windows command prompt just uses GetLongPathName, which returns the path with appropriate casing (however, it doesn't change the drive letter's casing).
If you want an uppercase drive letter, the GetShortPathName function returns the short path with the driver letter capitalized. You can then pass this short path to GetLongPathName, which will turn it into a properly cased long path, but this isn't what cmd does.
You can also use SHGetFileInfo, but it's not the easiest approach.
You can use the GetFullPathName API function to return the proper (case correct) path of the current directory, as in the following example:
TCHAR tchPath[MAX_PATH];
GetFullPathName(TEXT("."), MAX_PATH, tchPath, NULL);

when to call _findclose?

Note: Since problem is solved, I've added comments to my original posts.
According to "http://msdn.microsoft.com/en-us/library/6tkkkc1y%28v=vs.90%29.aspx", it stated as this:
*You must call _findclose after you are finished using either the _findfirst or _findnext function (or any variants). This frees up resources used by these functions in your application.*
--comment: it is vague, but what microsoft is trying to say is: some users just need to find the first file(they don't need to call _findnext), then call _findclose; some users called _findnext (they MUST have already called _findfirst), after finished using that, call _findclose. Actually _findnext can be called multiple times, while _findclose is only responsible to a handle, which is created by _findfirst.
And following is a piece of code that is widely used to list files in the directory. -- comment: it is correct.
For example, if there are 2 files and 1 directory in the directory, then:
.
..
ddd
file1.txt
file2.txt
_findfirst is called once. the handle's corresponding fileinfo is system directory "." (is that right?)
--comment: no. the handle is a group of files+directories, the fileinfo is acting as the "cursor". (fileinfo always contained the "name" field, I bet the implementation of _findnext is using the "name" to find the next in a group of files+directories specified by the handle)
_findnext is called 4 times. (the first argument is always the handle corresponding to ".", is that right?)
--comment: yes + no. The first argument is always the same handle; the handle is NOT corresponding to any fileinfo, but to a group of them.
My questions are:
Does "_findclose" be called ONCE is enough?
*--comment:* yes.
if _findnext will not change the handle value, how can it "remember" where to start to find the next file(or directory)? (sorry, maybe I was thinking in the "linked list" pattern.)
*--comment:* I bet is using fileinfo's name field. Just as in Windows Explorer, we sort the contents in a folder, given a file name, we can know their position in the list, so we can "find next".
Are there any harm to call _findclose more times than needed? (like crash or something)
*--comment:* a stupid question. Sorry!
Or is the following code wrong at all? If yes, what's the correct way to implement it?
--It is correct code.
// List the files in the directory
intptr_t file;
_finddata_t filedata;
file = _findfirst(desc.c_str(),&filedata);
if (file != -1)
{
do
{
cout << filedata.name << endl;
// Or put the file name in a vector here
} while (_findnext(file,&filedata) == 0);
}
else
{
cout << "No described files found" << endl;
}
_findclose(file);
I asked this because I've met an issue that an application is freezing a directory which can not be deleted if the process is alive. However, I can guaranteed that "_findclose" is called on every return value from "_findfirst". If I add "_findclose" after calling "_findnext", then will fix the issue perfectly. How can you help me to explain it?
--comment: pardon. don't use "guarantee" too easy. That's where the bug is.
Note: I don't have problem to understand what is a handle, like open a file, read/write/read/write..., close the file handle. I just find the documentations describing these three APIs are vague.
--comment: go to improve your english.
Thank you in advance.
Your calls to _findclose should match with your calls to _findfirst -- i.e., each time you call _findfirst, you should have a matching call to _findclose.
In the code above, since you have only one call to _findfirst, it's correct to have only one call to _findclose.
If you were doing a recursive search of subdirectories, then you'd end up with multiple calls to _findfirst as you descend the hierarchy, and matching calls to _findclose as you finish and ascend back up the hierarchy.
You only need to call _findclose once, when you are finished.
On Windows, a directory may be locked if it is the current directory of your process. Try calling _chdir.
If that doesn't work... are you opening any of the files in the directory you're searching? An open file may lock the directory as well.
It may be useful to let Process Explorer get a look at your app. It can tell you for sure what handle you have left open.