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.
Related
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()/
I'm looking for an efficient way to convert absolute filepath to a path relative to a specific directory.
Let's say we have to following structure:
D:\main\test1\blah.txt
D:\test2\foo.txt
With "D:\main" being the reference directory, then result would be:
blah.txt => "\test1\blah.txt"
foo.txt => "..\test2\foo.txt"
Any clue ?
Notes for the record:
It seems that:
there is no unified API function (cross-platform) for performing this
this question has been asked various times for other languages (though most answers take advantage of function PathRelativePathTo):
How to get relative path from absolute path
Getting a file path relative to a particular directory
How do I get a relative path from one path to another in C#
You are giving windows paths in your example. So, if it is acceptable for you to use the WinAPI functions, you can use PathRelativePathTo.
Here is the shortest solution I could figure out.
Algorithm is actually quite simple:
Given 1) a reference path (path to which result path will be relative to); and 2) an absolute path (full path of a file) :
while path parts are equals : skip them
when we come across a difference
add a ".." for each remaining part of reference path
add remaining parts from absolute path
The only limitation under windows is in case of distinct volume (drive letters differ), in which situation we have no choice but to return the original absolute path.
Cross-platform C source :
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
const char* path_separator = "\\";
#else
const char* path_separator = "/";
#endif
#define FILENAME_MAX 1024
char* get_relative_path(char* reference_path, char* absolute_path) {
static char relative_path[FILENAME_MAX];
// init result string
relative_path[0] = '\0';
// check first char (under windows, if differs, we return absolute path)
if(absolute_path[0] != reference_path[0]) {
return absolute_path;
}
// make copies to prevent altering original strings
char* path_a = strdup(absolute_path);
char* path_r = strdup(reference_path);
int inc;
int size_a = strlen(path_a)+1;
int size_r = strlen(path_r)+1;
for(inc = 0; inc < size_a && inc < size_r; inc += strlen(path_a+inc)+1) {
char* token_a = strchr(path_a+inc, path_separator[0]);
char* token_r = strchr(path_r+inc, path_separator[0]);
if(token_a) token_a[0] = '\0';
if(token_r) token_r[0] = '\0';
if(strcmp(path_a+inc, path_r+inc) != 0) break;
}
for(int inc_r = inc; inc_r < size_r; inc_r += strlen(path_r+inc_r)+1) {
strcat(relative_path, "..");
strcat(relative_path, path_separator);
if( !strchr(reference_path+inc_r, path_separator[0]) ) break;
}
if(inc < size_a) strcat(relative_path, absolute_path+inc);
return relative_path;
}
First thing you need to identify the file path separator as stated here.
const char kPathSeparator =
#ifdef _WIN32
'\\';
#else
'/';
#endif
Then, you need to write a function to compute a canonical absolute file path. You will have to use #ifdef _WIN32 again because there are specific windows treatment required (add current disk at the begining of path if none is present).
After that, remove all . in the path, and remove all .. with their previous directory.
Once this function is written, you need to use it twice to get your origin and target canonical absolute paths, and then as explains #Weather Vane you need to identify the common part in the two paths and to add the number of .. concatenated to the end of the target canonical 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
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.
I'm studying this book (Addison Wesley Windows System Programming 4th Edition) and I think its useless Im working on a searching code that support the recursive so it can go in deepth in files and directories the code is working ( I guess ) no syntax error but the output is not what I want the out put of the search is like:
not found
Now, here are the folders:
not found
Searching in d:\iust\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.
\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.
\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.
\.\.\.\.\.\..\e-books\.\.\.\.\E-BOOKS
The file name is: d:\iust\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\
.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\
.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\
.\.\.\.\.\.\.\.\..\e-books\.\.\.\.\E-BOOKS\*Test*
not found
Now, here are the folders:
not found
Searching in d:\iust\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.
\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.
\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.
\.\.\.\.\.\..\e-books\.\.\.\..
The file name is: d:\iust\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\
.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\
.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\.\
.\.\.\.\.\.\.\.\..\e-books\.\.\.\..\*Test*
not found
Now, here are the folders:
First I notiiced that what ever I do it will not search just inside the folder i specified but in all whole drive and the second annoying probem is the DOTS the . and .. those appear in each folder how can I avoid this problem. now as i said before Im using the book I mentioned before but I dont know I just dont like what i did is there a better way to form my code .
the code :
#include "stdafx.h"
#include <windows.h>
void SearchForFile(TCHAR *folder, TCHAR *file){
_tprintf(L"Searching in %s\n",folder); //just to show the state
TCHAR temp[1000];
_stprintf(temp,L"%s\\%s",folder,file); // here wrote into temp the location as folder/file
_tprintf(L"The file name is: %s\n",temp);
HANDLE f;
WIN32_FIND_DATA data;
f=FindFirstFile(temp,&data);
if(f==INVALID_HANDLE_VALUE){
_tprintf(L"not found\n");
}
else{
_tprintf(L"found this file: %s\n",data.cFileName);
while(FindNextFile(f,&data)){
_tprintf(L"found this file: %s\n",data.cFileName);
}
FindClose(f);
}
_stprintf(temp,L"%s\\*",folder); // "d:\*" for example
_tprintf(L"Now, here are the folders:\n");
f=FindFirstFile(temp,&data);
TCHAR temp2[1000];
if(f==INVALID_HANDLE_VALUE){
_tprintf(L"not found\n");
}
else{
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
//_tprintf(L"found this directory: %s\n",data.cFileName);
_stprintf(temp2,L"%s\\%s",folder,data.cFileName);
SearchForFile(temp2,file);
}
while(FindNextFile(f,&data)){// _tprintf(L"%d %d\n",data.dwFileAttributes,FILE_ATTRIBUTE_DIRECTORY);
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
// _tprintf(L"found this directory: %s\n",data.cFileName);
{
_stprintf(temp2,L"%s\\%s",folder,data.cFileName);
SearchForFile(temp2,file);
}
}
FindClose(f);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
SearchForFile(L"d:\\test", L"*Test*");
return 0;
}
You have to filter out the . and .. pseudo-folders found in every folder.
Roughly, in your recursive branch:
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0
&& data.data.cFileName != "."
&& data.data.cFileName != "..")
In general, you should skip "." and ".." directories, they are synonyms for "current" and "parent" directory.
Pretty much no matter how you find the contents of a directory on Windows the first matches will be '.' (the current directory) and '..' (the parent directory). You probably want to ignore both of them.
Usually you explicitly test for and skip the "." and ".." subdirectories that are present in all directories (but the root). The code you're using searches subdirectories recursively, and since you're not ignoring the ".." directory, it'll search that, which will eventually lead to the root directory, and search all subdirectories from there -- meaning it'll search the whole disk.