Cross-platform directory path validation in C (Linux and Windows) - c

I have a C function that accepts directory path as a string. The function creates a directory at the given path.
int create_directory(const char *path) {
// given path may be absolute or relative
// step 1:-need to validate the given path(cross platform for both Linux and windows)
// what are the criteria for path validation?
// step 2:- check permission about user accessibility ,means can not create directory, if path is like /usr/bin or /root).but in root login then we create.
So what are the criteria for validation?
// step 3:-if directory, subdirectory already exist at the path, then return?
// step 4:-if not exists then create directory ;
}
basically I have problem in step 1 and step 2. I am not able to identify what the exact criteria for path validation are.

The best way to check the validity of a path given to you is to try the operation with it. The OS will give you an error code (errno or GetLastError() or something) and you can use that to determine why it wasn't possible.

I would let the underlying OS perform the validation.
Create the directory and then check the error code.

Linux uses the "/" to separate between directories in a given path while windows uses "\" plus almost all the windows paths begin with C:\\ or (D:\\ it doesn't matter the most important is the :) so you can just use a strchr() to look for those signs or you can just use perror() which is much easier (you'll have to include <errno.h>)

Related

Understanding Lua's os.tmpname() on Windows

I'm trying to use Lua's os.tmpname() on Windows (which uses tmpnam() under the hood), and I'm a bit puzzled by the filenames it is returning.
> print(os.tmpname())
\s3e8.
If I feed it directly to Lua like io.open(os.tmpname(), "w"), it will attempt to create the file in the root directory of the current drive. This seems pretty inappropriate, since we often don't have the permission to do that.
But according to this thread:
https://mingw-users.narkive.com/L7VR1gxX/temporary-file-woes
This is apparently supposed to be a path relative to the current directory. They mentioned this snippet from a Microsoft documentation:
Note than when a file name is prepended with a back slash and no path
information, such as \fname21, this indicates that the name is valid
for the current working directory.
But I can no longer find the documentation they mentioned in the thread.
I googled around, trying to find the latest documentation and found this:
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/tempnam-wtempnam-tmpnam-wtmpnam?view=msvc-160
This is the generation rules mentioned in the documentation above:
_tempnam will generate a unique file name for a directory chosen by the following rules:
If the TMP environment variable is defined and set to a valid
directory name, unique file names will be generated for the directory
specified by TMP.
If the TMP environment variable is not defined or if it is set to the
name of a directory that does not exist, _tempnam will use the dir
parameter as the path for which it will generate unique names.
If the TMP environment variable is not defined or if it is set to the
name of a directory that does not exist, and if dir is either NULL or
set to the name of a directory that does not exist, _tempnam will use
the current working directory to generate unique names. Currently, if
both TMP and dir specify names of directories that do not exist, the
_tempnam function call will fail.
I do have the TMP environment variable defined, but Lua always generates the kind of paths I mentioned at the top.
So really, I have two questions:
Is this actually supposed to be a relative path?
If so why does it always generate a relative path, instead of using the standard TMP variables?
I'm testing this with Lua 5.2 from LuaBinaries and the Lua statically built into shinchiro's mpv builds.
According to this thread on lua-users.org you can try passing null.
well i solved it using tmpname(NULL,NULL)... it considers the
temporary directory of the system.
when i use tmpnam() on windows on a non-writable root, the filename
generated (\something) is not writable...
i guess it's an implementation bug
Also note the Lua 5.2 Reference Manual
When possible, you may prefer to use io.tmpfile, which automatically removes the file when the program ends.

Directory trees in C

So I have an assignment for my finals homework. It wants me to make a directory tree with some commands, similar to CMD. For example it will give me "make " and I will add directories to the tree. I got all the commands, syntax checking etc. down but I can't think how can I create the tree.
I thought about making a general tree for it, but there's a problem. When I add new folders, I need to check if it's already there and print a message if it is. I don't know a lot about tree structure but from what I know, to check them, I need to do firstChild, secondChild... until there is none which seems not the best way to do it.
I need ideas on this. I don't want you to do my homework, just a guideline for me to study would be more than enough.
To check if a directory path exists you can use fstat (see: https://linux.die.net/man/2/fstat).
But if you have the full path, you will parse that and check all if every part's parent exists.
For example if the path is /usr/local/bin/test you should check if /usr exists, then /usr/local, then /usr/local/bin and finally /usr/local/bin/test.
To do this you could write a recursive function calling itself with the last folder part stripped (unless you're at the root level) before checking if the specified path exists.

How to change the current directory to a designated directory using chdir() in c?

EDIT
The existed directory is not necessarily a sub-directory of the home directory. It can be a sub-directory of a sub-directory of the home directory.
End of EDIT
I am reading a user input (e.g., cd existedDirectory) to change the current directory to the "existedDirectory". I know that
chdir(getenv("HOME"));
can change the current directory to home directory, so I tried the following methods:
chdir(getenv("/existedDirectory"));
chdir(getenv("existedDirectory"));
chdir(getenv("~/existedDirectory"));
chdir("/existedDirectory");
chdir("existedDirectory");
chdir("~/existedDirectory");
Nothing worked. Any help will be greatly appreciated.
chdir takes a string argument with a path to change to. It does no other special handling (environment vars or home or anything else), so you if you want any of those things, you need to build a string to pass into it.
chdir("/existingDirectory");
which change to and existing directory in the root directory -- it has an absolute path. So it has to be one of the directories you see when you run ls /.
chdir("exisitingDirectory");
will change to an existing subdirectory of the current director.
If you want to change to a subdirectory of your home directory, you need something like:
char path[PATH_MAX];
sprintf(path, "%s/%s", getenv("HOME"), "subdir");
chdir(path);
chdir() in C only affects the process, which calls it. Your shell and your program are two different processes, which run separately. So, the environmental variable $PWD, which indicates the working directory, will only be changed for your application. Check this resource, too.
Note:chdir() doesn’t change the working directory of current shell. Because when the program is executed in the shell, the shell follows fork on exec mechanism. So, it doesn’t affect the current shell.

How to save file in custom place in C

I'm working with C right now. And there's a problem. I don't know how to save a FILE in custom place. When I run *.exe file, it saves them where code is placed. So how to make it save FILEs where I want it to be?(I can input a path)
a FILE is actually a long type that addresses a path on your computer.
Whether you use linux, windows, etc, the common thing about the paths is the idea that there are relative paths or absolute paths.
From what I've understood you probably did use the relative path, and I can guess you didn't specified a path at all, but only the file name.
Notice that a file's name alone is placed relatively to the path of the program you are running.
To fix your problem you might want to give an absolute path (such as "/home/user/" on linux or "C:\Users\user" on windows [pay attention for the escaping backslash]).
You can do it by something like this:
FILE *output = fopen("/home/user/output.txt", "w");
(where "w" means writing permissions to the file at the given path).
Hope this answers your question.

Creating a unique temporary directory from pure C in windows

I'd like to create a unique temporary directory in Windows from some C
code (not C++ or C#). I want to do this so that I can put some temp
files in the directory, and then delete them all easily when I'm done
(by removing the directory recursively).
I'm essentially looking for an equivalent of the linux
mkdtemp
function. There is a C# answer here, and responses on this
question
suggest using Boost. But since I'm using C, those solutions don't work
for me.
The best I've been able to come up with so far is to use
GetTempFileName
followed by CreateDirectory,
but the problem there is that if I ask
GetTempFileName
to create a unique file name, it will also create the file (which I
don't want, since I want to make a directory instead).
Relatedly, there's
GetTempPath,
which returns the location of the user's temp folder from environment
variables - but since I want to create my own directory that I can
safely delete later, I still need to create a directory inside any
path it would return.
It looks like if I want a unique directory to be created, I'll have to
create a temp file, get the name, delete it, and then create a
directory with the same name - which sounds very messy.
Any other ideas?
You can use what GetTempPath returns concatenated with a Guid to ensure uniqueness of the directory. You can create a Guid using UuidCreate or CoCreateGuid Function.
To delete recursively the directory, there is an example here in pure C: How to remove directory recursively? based on FindFirstFile, FindNextFile, DeleteFile and RemoveDirectory.
There is also SHFileOperation but it's more heavyweight and is based on the Windows Shell functions, and the Shell DLLs are not always wanted, especially if you're writing server code.
Use GetTempPath then CreateDirectory with a random name under it, optionally retrying if CreateDirectory fails due to it already existing. But if your name generation is good enough, the likelihood of a collision with an existing name is much smaller than the likelihood of a blackhat guessing your password or even your private key, so you might as well ignore it.
Use _tempnam tmpnam_s to create a filename that doesn't exist yet, and then use CreateDirectory to create the directory. There's technically a race condition if you do this, in that another process could potentially create a file or directory with that name in the time in between when you generate the filename and when you create the directory, but the odds of that are rather unlikely. To protect against that, you can loop until you succeed.
For recursively removing a directory tree, you can use SHFileOperation. Alternatively, you can do the directory traversal yourself with FindFirstFile/FindNextFile, DeleteFile, and RemoveDirectory.
If you want to remove the directory automatically upon exiting, register a function using atexit. This will only work for normal program termination (i.e. via the exit function or via returning from main/WinMain). This will not work for abnormal program termination (e.g. via abort, an access violation, someone else calling TerminateProcess, etc.).

Resources