How to check if path is a subdirectory of another - c

How I can check if path is a sub-directory of another ?
I want to check this because I don't want to allow the user to go forward of the path given as argv of my program.
I did that :
bool can_move(char *base, char *new)
{
return (strncmp(base, new, strlen(base)) == 0
&& (access(new, F_OK) == 0));
}
But the problem is how can I mange the './' and the '../' ?
Thanks !

Get the realpath() for argument and path where the user want to go .
Be sure that user realpath() is argument realpath() or start with argument realpath()/

Related

My cd function does not go to the home directory

I am building a custom shell in c, and one of the requirements is that the folder from while you run the program must be the "home" folder.
That is, if you type in just cd or cd ~ you should get to that directory. I have implemented it, but it is not working.
char *basedir;
void init_prompt()
{
getcwd(cwd,100);
basedir = cwd;
}
void cd_me(char **argv)
{
chdir(argv[1]);
if(getcwd(cwd,100)!=0)
{
;
}
if(strcmp("~\0",argv[1])==0||strcmp("\0",argv[1])==0)
chdir(basedir);
}
Any suggestions on how to fix this?
Also when I print basedir I am getting the correct output.
char *basedir;
basedir = cwd;
You make basedir a synonym to cwd. Whenever cwd changes, basedir follows. It's a pointer, it cannot remember its own string, it can only point to someone else's string.
You must make a copy instead.
char basedir[100];
strcpy(basedir,cwd);
Add bounds checks and error handling as needed.

C : Unexpected behaviour, wrong list returned?

I'm working on an assignement where I'm asked to code some of unix's ls.
The part I'm having trouble with is the -R option.
Some context :
I'm using a structure containing 2 lists, one for files and the other for directories that would be passed as arguments when running my ls. If there are no argument other than options, I create a dir node containing ".".
Without the -R option, if there are files in the list, I pass a copy of it to the display function, then clear the files list. If there are none but there are directories, I open one, read and copy its content to the files list, free the current directory node, and proceed as with regular files list. This works just fine.
With the -R option, though, I do the exact same thing, but when reading a directory, if there is a sub directory in it, I add the latter to the directory list. In theory this should work just fine and prevent the use of recursivity, but for some reason the list returned to be displayed only contains directories, no files. And this problem seems to only appear when there's no argument other than options...
Here's the code :
t_list *ft_output_bigr(t_input *input)
{
t_list *dir_content;
DIR *dir_stream;
struct dirent *buf;
if (!input->files->content && !input->dir->content)
return (NULL);
if (input->files->content)
return (ft_lstcpy_and_del(input->files));
dir_stream = opendir(input->dir->content);
ft_lstfreeone(&input->dir, input->dir);
while ((buf = readdir(dir_stream)))
{
dir_content = ft_lstnew(buf->d_name, sizeof(buf->d_name));
ft_lstadd(&input->files, dir_content);
if ((ft_is_dir(buf->d_name)) && ft_strcmp(buf->d_name, ".") != 0
&& ft_strcmp(buf->d_name, "..") != 0)
{
ft_lstadd(&input->dir, dir_content);
}
}
closedir(dir_stream);
return (ft_lstcpy_and_del(input->files));
}
And here is the function that calls it, which handles options and display.
int ft_process_input(t_input **input)
{
t_list *output;
while ((output = (ft_strchr((*input)->opt, 'R')) ? ft_output_bigr(*input)
: ft_output(*input)))
{
output = (ft_strchr((*input)->opt, 'a')) ? output
: ft_rem_hidden(&output);
output = (ft_strchr((*input)->opt, 't')) ? ft_t(&output)
: ft_parse(&output);
output = (ft_strchr((*input)->opt, 'r')) ? ft_lstrev(&output) : output;
output = (ft_strchr((*input)->opt, 'l')) ? ft_l(output) : output;
while (output)
{
ft_putendl(output->content);
ft_lstfreeone(&output, output);
}
}
return (1);
}
I checked the files list right before returning it, and it seems ok. But for some reason, once it's passed to process_input, bam, only directories left.
So yeah, I'm lost here. Out of ideas to try... Help ? :D
Edit : Adding informations about behaviour.
So I thought my list was ok before the return because I checked the first node and it was ok. Silly me. The list is actually screwed before the return, which makes more sense at least.
So what seems to be happening is the files and dir lists are mixed up somehow, and when I return input->files, input->dir is returned instead.
I'm hinting at something along the line of both lists pointing to the same head (the head of the dir list) as I lstadd dir_content to both. I'll try to add a copy of dir_content or something, and be back with news.
Ok, fixed it.
Moral of the story : You can't simply add a node to 2 lists and expect to have 2 different lists as a result.

How to get /etc/ directory

I have function:
gint isfileexists(gchar *filename)
{
struct stat buffer;
gint i = stat(filename, &buffer);
if (i == 0) {
return 1;
}
return 0;
}
and if I call them:
isfileexists("/etc/myfile")
it search "myfile" in "/home/user/etc/myfile". How to do this well?
It should only look for /home/USER/etc/myfile if:
you leave off the leading / when calling isfileexists; and
that directory /home/USER is your current working directory.
In other words, if the argument is a relative path name.
Since you have the leading /, it will be an absolute path name and should access /etc/myfile.
If I've misunderstood and you actually want the one in your home directory, you can use getenv("HOME") to get your home directory and then append /etc/myfile with strcat. That will also work regardless of your current working directory.

a recursive function to manipulate a given path

I am working on modifying the didactic OS xv6 (written in c) to support symbolic links (AKA shortcuts).
A symbolic link is a file of type T_SYM that contains a path to it's destination.
For doing that, i wrote a recursive function that gets a path and a buffer and fills the buffer with the "real" path (i.e. if the path contains a link, it should be replaced by the real path, and a link can occur at any level in the path).
Basically, if i have a path a/b/c/d, and a link from f to a/b, the following operations should be equivalent:
cd a/b/c/d
cd f/c/d
Now, the code is written, but the problem that i try to solve is the problem of starting the path with "/" (meaning that the path is absolute and not relative).
Right now, if i run it with a path named /dir1 it treats it like dir1 (relative instead of absolute).
This is the main function, it calls the recursive function.
pathname is the given path, buf will contain the real path.
int readlink(char *pathname, char *buf, size_t bufsize){
char name[DIRSIZ];
char realpathname[100];
memset(realpathname,0,100);
realpathname[0] = '/';
if(get_real_path(pathname, name, realpathname, 0, 0)){
memmove(buf, realpathname, strlen(realpathname));
return strlen(realpathname);
}
return -1;
}
This is the recursive part.
the function returns an inode structure (which represents a file or directory in the system). it builds the real path inside realpath.
ilock an iunlock are being used to use the inode safely.
struct inode* get_real_path(char *path, char *name, char* realpath, int position){
struct inode *ip, *next;
char buf[100];
char newpath[100];
if(*path == '/')
ip = iget(ROOTDEV, ROOTINO);// ip gets the root directory
else
ip = idup(proc->cwd); // ip gets the current working directory
while((path = skipelem(path, name)) != 0){name will get the next directory in the path, path will get the rest of the directories
ilock(ip);
if(ip->type != T_DIR){//if ip is a directory
realpath[position-1] = '\0';
iunlockput(ip);
return 0;
}
if((next = dirlookup(ip, name, 0)) == 0){//next will get the inode of the next directory
realpath[position-1] = '\0';
iunlockput(ip);
return 0;
}
iunlock(ip);
ilock(next);
if (next->type == T_SYM){ //if next is a symbolic link
readi(next, buf, 0, next->size); //buf contains the path inside the symbolic link (which is a path)
buf[next->size] = 0;
iunlockput(next);
next = get_real_path(buf, name, newpath, 0);//call it recursively (might still be a symbolic link)
if(next == 0){
realpath[position-1] = '\0';
iput(ip);
return 0;
}
name = newpath;
position = 0;
}
else
iunlock(next);
memmove(realpath + position, name, strlen(name));
position += strlen(name);
realpath[position++]='/';
realpath[position] = '\0';
iput(ip);
ip = next;
}
realpath[position-1] = '\0';
return ip;
}
I have tried many ways to do it right but with no success. If anyone sees the problem, i'd be happy to hear the solution.
Thanks,
Eyal
I think it's clear that after running get_real_path(pathname, name, realpathname, 0, 0) the realpathname cannot possibly start with a slash.
Provided the function executes successfully, the memmove(realpath + position, name, strlen(name)) ensures that realpath starts with name, as the position variable always contains zero at the first invocation of memmove.
I'd suggest something like
if(*path == '/') {
ip = iget(ROOTDEV, ROOTINO); // ip gets the root
realpath[position++] = '/';
} else
ip = idup(proc->cwd); // ip gets the current working directory
P.S. I'm not sure why you put a slash into the realpathname before executing the get_real_path, since at this point you don't really know whether the path provided is an absolute one.
Ok, found the problem...
The problem was deeper than what i thought...
Somehow the realpath was changed sometimes with no visible reason... but the reason was the line:
name = newpath;
the solution was to change that line to
strcpy(name,newpath);
the previous line made a binding between the name and the realpath... which can be ok if we were not dealing with softlinks. When dereferencing a subpath, this binding ruined everything.
Thanks for the attempts

Trying to open a relative path in Ubuntu doesn't work

I'm trying the open a relative path in Ubuntu , but after opening the first folder - called 14 - the code fails to open the folder inside - called 15:
int pathsCtr; // number of folders in RelativeArray
char ** RelativeArray; // the folders in the relative path, currently:
RelativeArray[0] = "14";
RelativeArray[1] = "15";
// some code before
if (pathsCtr > 0 && flag == TRUE) // then we have a relative path
{
int j = 0;
while (j < pathsCtr) // run until the last path and open every one
{
printf("\n%s\n" , RelativeArray[j]);
dirp = opendir(RelativeArray[j]); // open all directories until the last one
if (dirp == NULL)
return -1;
j++; // proceed to the next directory
}
flag = FALSE; // turn off the flag , we'll never go near this again
}
When j == 0 this line : dirp = opendir(RelativeArray[j]); works and dirp is not NULL.
But when j == 1 that line dirp = opendir(RelativeArray[j]); fails and dirp is NULL .
What am I doing wrong?
EDIT:
Assume that I'm doing malloc for RelativeArray before the above code .
opendir() opens a directory for reading its contents, but it does not change the working directory of the process.
To access a subdirectory, you will have to specify it by its fully path relative to the current working directory (or else its absolute path).
You can probably do this by concatenating your strings with an appropriate separator character.
Since you don't seem to do anything with the directory stream pointer returned by opendir() other than check that it's non-null, there's a good chance this is not the function you want to be using. You may want to look at chdir() instead (man 2 chdir) but do think about any undesired consequences.

Resources