How to convert absolute path to relative in c linux - linux

I would like to know how an absolute path of a symbolic link can be converted to relative based on a given directory (that includes the linked file) in c language on linux (Ubuntu) OS.
I thought searching for the sub-string of the relative path, but what if it already exists higher in the folder's hierarchy?
Here is a more specific description of what I want to do:
Relative path:
folder/folder1/folder2
Absolut path:
/home/giorgos/Desktop/folder/folder1/folder2/a.pdf
changed to
/home/giorgos/Desktop/myfolder/folder1/folder2/a.pdf
Obviously I cant' simply search for and replace "folder/", consider this case:
/home/giorgos/Desktop/folder/folder/folder/folder1/folder2/a.pdf
It can be searched both forwards and backwards and if replaced it still gives a wrong output
Only if I knew the relative path I could search the absolute backwards and replace it, then the output would be correct:
/home/giorgos/Desktop/folder/myfolder/folder/folder1/folder2/a.pdf

Converting a path to relative is a matter of first seeing how many base atoms are shared between the two paths, and then inserting ../ to navigate backwards up the tree before navigating down the correct branch. IE going from: /foo/bar/some/path to /foo/other/path you'll first see that they share /foo, to navigate upwards to that point you need 3 ../, turning the relative path into /foo/../../../other/path . There's a boost::filesystem example for C++ here , save for the C++ & boost::filesystem the same can be done in C.

I'd be seriously tempted to make the decision, if I were writing this tool, that absolute symbolic links should have the same value when moved somewhere else in the filesystem -- the user wanted a very specific file. And, relative symbolic links should have the same value when moved somewhere else in the filesystem -- the user wanted the links to work regardless of where the directory tree was rooted.
But if the two types of links were intermixed, then you'd have some more work to do -- which is where I assume you are now. (Unix programs are often not that forgiving about guessing a user's intent; if you just readlink(2) and symlink(2) exactly what the filesystem says, your program will never be surprising.)
rsync(1) might have some source code you can use -- or at least learn from. The --safe-links command line option causes rsync to ignore absolute symbolic links and relative symbolic links that point outside the trees it was instructed to copy. This isn't canonicalizing paths to relative as you wish but it may provide sufficient code for discovering which links point outside the directory tree in question.
Slightly related; the Linux-specific symlinkat(2) system call may make it easier for you to create your symbolic links. (The family of ...at() system calls are something like providing a process with multiple "current working directories" without forcing you to make all the fchdir(2) calls yourself.)

Well at first I didn't consider the following as important information, but with the help of a function I found out the absolute path to the original and copy directories.
This way I could finally get the original's folder "relative path" (path starting from original folder) change the root node of the dir's tree name to the copied folder's then get the absolute path of the copied folder and append the copied "relative path" and that was it!
realpath(directory,absolutePath);
This is what my code looks like :
readlink(A[i].str, oldLink, NAMESIZE);//A is the struct I keep the paths to directory entries
k=0;
j=strlen(absolutPath);
while(oldLink[j]!='\0')
{
fixLink[k]=oldLink[j];
j++;
k++;
}
strcpy(tmpLink,newAbsolutPath);
strcat(tmpLink,fixLink);
symlink (tmpLink,tmpPath);//tmpPath is the name of the link, tmp link is the absolute path to the actual file
//tmpPath is built almost the same way
So far it runs without any bugs

Related

Clarification of Rust File Paths and access

Very new to Rust and am looking for clarification about rust file paths that are outside the project directory. I would expect reading a .txt file from say the desktop to look something roughly like this:
fs::read_to_string("./Desktop/test.txt");
However, this does not seem to work. Is this an issue with the file path listed or does Rust only allow access to files in the project directory? If this is the default case how does one allow access to files elsewhere in the system outside the current working directory?
Say the project is in Documents and we want to access some text file on the Desktop.
Found the answer, seems the path that I am looking for is like this :
fs::read_to_string("/Desktop/test.txt");
Seems the "." was looking in the current directory.
When you open a path that starts with ./, it is relative to the current working directory.
Assuming that the program does not change the working directory itself, that would be whatever directory the user was in when they started the executable.
Note that it is not necessarily the project directory: when you are developing your program, you will probably run it via cargo run, but when it is ready you would most likely copy the target executable into a directory that is in the path. The working directory can be completely different to the directory in which the executable is placed.
Your program can find out the current working directory by calling std::env::current_dir
If you want a path that does not depend on the working directory, you can use an absolute path, ie. starting with /.
Rust is no different to any other programming language in this respect. In particular, files are not opened in respect to the project dir.
As specified, the path will be relative to the working directory of the process. If the working directory isn't your home directory, then you need to be more specific about where the file is.
Note that the working directory can change depending on how you run the program. The link above has more information on this topic.
You can obtain your user's desktop directory using desktop_dir from the dirs crate, which will make the working directory irrelevant in this particular case. It will also correctly determine the user's desktop directory on many different operating systems.
fs::read_to_string({
let mut path = dirs::desktop_dir().expect("no desktop directory");
path.push("test.txt");
path
})

How to reference or link files and folders inside a git repository to match these criteria?

I've encountered a problem long time ago which I couldn't solve, but I'm curious whether it's possible to fulfill ALL of the below listed criteria at once or not.
The solution what I was looking for can:
somehow refer to an existing file or folder from another folder of the same git repo
basically reach the content of the file or folder from another subfolder, see the content(s) as if they were on the another path as well
e.g.: if ./path/to/folder is referred from ./another_path/different_folder, then every file in ./path/to/folder/* is visible on path ./another_path/different_folder/*
e.g.: if ./path/to/file is referred by ./another_path/different_file, then by reading/writing content of the different_file, the original file is read/modified
store the referred file only once in git repo
don't want to make a copy of the file to another path and maintain changes in both files simultaneously
be able to use multiple references for a single file
be able to use relative paths
make it work on both Windows and Linux
As if I can remember, some of the problems were while experimenting with this:
the paths were broken after the repository was pulled to a different path (I assume they were not relative, but absolute)
the Windows style links are special files, were not working on Linux
the symlinks can't handle relative paths correctly on the Windows system
the hardlinks resulted duplicating files in Windows
(I can't remember exactly which if these might be incorrect, but I'll experiment with the problem again and try to update this question.)
Is there any workaround for this problem?
Thank you for any help!
Please note (in case you would like to mark this question as a duplicate), that there are other similar questions here, but none of those questions define this set of the criteria, therefore it can't be a duplicate.

Where do I put sublime_text_3

I just unzipped sublime_text_3_build_3143_x64.tar.bz2 and have a nice copy of the sublime_text_3 directory in my downloads folder.
Where is the right place to put this file in Centos? Maybe somewhere in /user/local/?
Also do I create a link to the executable or set a Path?
Just looking for favorite (best?) practices.
As has been pointed out in the linked article in the question comments, /opt is preferred by some, and in fact according to this answer, /opt is where you would locate "unbundled packages". Of course, it also goes on to say that these sorts of packages should also package the binary in a bin subfolder, which Sublime does not, for what that's worth.
If you want to follow best practices, that's probably where you should place the folder. If nothing else, I would assume that any Linux OS that has a package manager for doing upgrades is going to stay well clear of /opt based on what it's used for, which will make sure that something untoward can't happen.
As to whether you would create a symlink or add that folder to the path, I'm not so sure. My own personal philosophy is that the PATH isn't something that needs to have an entry for every application that I install.
My own recommendation would be to create a symlink somewhere that's already in the path and you're good to go. The linked article mentions putting the link in /usr/bin. The Filesystem Hierarchy Standard says of this path:
This is the primary directory of executable commands on the system.
I would take from this that this is an acceptable path to put the symlink in.
In the end, it doesn't matter to Sublime where the folder is placed, since it determines the location of the shipped packages based on where it's binary is located, and the configuration information is always in a known place.

Which path can i use inside my program that will fit other computers? (that also have ubuntu)

I made a program in QT c++ that creates some files and i want them to be saved in a specific directory, i created a directory and i moved all the program there so i can use that same directory to save them, but when i write the path to save the files i have to write:
/home/"the name of my computer"/my_program/file.txt
and i want to use this same program in different computers. I also tried just writing:
my_program/file.txt
but it doesn't work.
Your relative path approach was already good, but a relative path is treated as relative to the working directory of the process and that depends on how the program is started.
E.g. if you start it from a shell, then the shell's current working directory will be the program's, if you start it from a launcher menu, it is often the user's home directory, but could be the location of the binary, etc.
So it is better to create a path based on well known base paths. such as the user's home directory, see QDir::home() or the a common location depending on type of data, see QStandardPaths
Did you try home directory path with "~/", many applications save their settings in ~/.applicationName directory

How does ${path} work, in this tutorial

I'm sure this is one of the dumbest problems asked on this site, but I am very new to linux, and a little out of my depths. I'm working off of this tutorial here and am stuck on the "add the path" and verify steps.
For this one the tutorial told me to use this:
export PATH=${PATH}:${DTITK_ROOT}/bin:${DTITK_ROOT}/utilities:${DTITK_ROOT}/scripts
I have already defined DTITK_ROOT, and have a few questions about the above instructions.
Should the ${} be left around the DTITK_ROOT?
My DTITK_ROOT is the full path (I think that's the right term) to the file I extracted the program to, should I change that?
What do I write for ${PATH} in that case? I understand that I'm supposed to replace it with something, but I don't know what. Everything I've tried doesn't pass the verify step.
I'm sorry if it seems like a dumb or really simple question, but I don't even know any keywords to google in order to find how to get the answer.
Yes. This is how you access the path stored in DTITK_ROOT. This is called parameter expansion. You can read more about it here.
No, don't change anything. Also, a more commonly used term is absolute path, in comparison to relative path. The absolute path is a path from the root directory, /. Relative path is a path from your current working directory. You can read more about paths in general and the difference between absolute and relative paths here.
You don't replace it with anything. Once again, parameter expansion comes into play and this will be replaced with what is already stored in your path variable. So really all this command is doing is taking your path variable, adding some more paths to it, and then storing it back into your path variable. If you didn't know, the path variable contains paths to all executable files that you would like to execute without typing the full path. Here is a good discussion on path variables, along with other environment variables.
1st command takes care of path
export DTITK_ROOT=mypathonSystem/dtitk
2nd command
export PATH=${PATH}:${DTITK_ROOT}/bin:${DTITK_ROOT}/utilities:${DTITK_ROOT}/scripts
I am not too sure but I think second command should run as is since you defined DDTITK_ROOT in first command
${PATH} is letting the system know where the resources can be found at
have you tried running first command, then running second command unmodified?
Should the ${} be left around the DTITK_ROOT?
Yes. In the case of the shell, it is not essential here because the / that follows the $DTITK_ROOT is enough to signal that we have reached the end of the variable name, but doing ${DTITK_ROOT} explicitly says that the variable name is DTITK_ROOT and not that plus whatever characters might be on the end of it. Other programs (such as make) which allow you to write shell commands to execute might not be so accommodating - make would think that $DTITK_ROOT would be the value of $D followed by the literal characters TITK_ROOT. So, it is a good practice to just get used to putting {} around shell variable names that are longer than a single character.
My DTITK_ROOT is the full path to the file I extracted the program to, should I change that?
If you mean the full path to the directory that you extracted the program to, then that is what you should use. I am assuming that you have something like "export DTITK_ROOT=/Users/huiz/unix/dtitk" (per the example).
On thing you can do is to verify that the value of DTITK_ROOT is available by executing a "echo ${DTITK_ROOT}" to verify that it has the proper value.

Resources