$PWD vs getcwd()

stackoverflow.com/questions/1951742/how-to-symlink-a-file-in-linux

To get the current working directory, there are various ways like command ‘pwd’, variable ‘$PWD’, getcwd(), etc. In this post, I would like to go through two methods ‘$PWD’ and ‘getcwd()’, the benefits and drawbacks of each.

$PWD

The POSIX definition of $PWD is

PWD

This variable shall represent an absolute pathname of the current working directory. It shall not contain any filename components of dot or dot-dot. The value is set by the cd utility.

To put in layman`s terms $PWD is an environment variable. This variable returns the path of the current folder. If it is a symlink, $PWD variable returns the path set by the link but doesn`t resolve it to its original path.

Try:

$ echo $PWD
/home/vineet

Since this is a variable, it can be used to set to a particular shell/ environment.

getcwd()

The man page of getcwd() says

getcwd()

The getcwd function returns an absolute file name representing the current working directory, storing it in the character array buffer that you provide. The size argument is how you tell the system the allocation size of buffer.

In layman`s terms, getcwd will return the absolute path of the current working directory. It takes a buffer array as input and returns the array in which the path wil be stored.

Try:

test.c

#include
#include
#include
#include
int main() {
char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) != NULL)
fprintf(stdout, “Current working dir: %s\n”, cwd);
else
perror(“getcwd() error”);
return 0;
}

Output

$ ./try
Current working dir: /home/vineet/GSoC/New/Test

Except for few cases, mostly both these will yield the same output. Let us look at cases where this will vary.

Differences in the outputs:

Symlinks:

When symlinks are used, both these will result in a different answer.

For example, I am currently in the folder ‘/home/vineet/GSoC/New’. Then I created a new folder ‘Test’. Then I create a symlink to Pharo folder and move to that.

$ mkdir Test

$ls -l

total 0

$ln -s /home/vineet/GSoC/Pharo /home/vineet/GSoC/New/Test

$cd Test

$ls  -l

total 0
lrwxrwxrwx 1 vineet vineet 23 May 15 21:01 Pharo -> /home/vineet/GSoC/Pharo

$cd Pharo

Then I create a file test.c in the folder Pharo which contains the code

#include
#include
#include
#include
int main() {
char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) != NULL)
fprintf(stdout, “Current working dir: %s\n”, cwd);
else
perror(“getcwd() error”);
fprintf(stdout, “PWD: %s\n”, getenv(“PWD”));
return 0;
}

Then I compiled and ran this code.

$ ./try
Current working dir: /home/vineet/GSoC/Pharo
PWD: /home/vineet/GSoC/New/Test/Pharo

Note the difference? getcwd() was giving the actual path of the folder. While PWD wasn`t resolving the path and is still using the current structure.

Implementing in Pharo:

I have implemented two functions in Pharo using the above two implementations (followed the same directory structure).

Using getcwd():

Method:

getPwdViaFFI: arg1
“This method calls the Standard C Library getcwd() function. The name of the argument (arg1) should fit decompiled version.”
^ self ffiCall: #( String getcwd (String arg1,256) ) module: LibC

Implementation:

buffer:= String new:100.
OSEnvironment current getPwdViaFFI: buffer.

-> ‘/home/vineet/GSoC/Pharo/New_Pharo1’

And

Using getenv(‘PWD’): (This already exists)

Method:

getEnvViaFFI: arg1
“This method calls the Standard C Library getenv() function. The name of the argument (arg1) should fit decompiled version.”
^ self ffiCall: #( String getenv (String arg1) ) module: LibC

Implementation:

OSEnvironment current getEnv: ‘PWD’.

-> ‘/home/vineet/GSoC/New/Test/Pharo/New_Pharo1’

For ‘PWD’ I also tried:

getPwdViaFFI
“This method calls the Standard C Library getenv() function. The name of the argument (arg1) should fit decompiled version.”
^ self ffiCall: #( String getenv(“PWD”) ) module: LibC

And called using

OSEnvironment current getPwdViaFFI

Apparanty, this was killing the whole process. (?)

Using chdir():

Initially, if both $PWD and getcwd() are called from a directory and if chdir is used to change directory to it parent directory. Now, if both $PWD and getcwd() are called, getcwd() gives the correct path, while $PWD doesn`t give the right path. This is because when chdir() is used, $PWD should be specifically updated to the new path. On the other hand, getcwd doesn`t need any update.

Try:

#include
#include
#include
#include
using namespace std;
int main()
{
char path[256];
getcwd(path, 256);
cout << path << endl;
cout << getenv("PWD") << endl;
chdir("../");
getcwd(path, 256);
cout << path << endl;
cout << getenv("PWD") << endl;
}

Output:

/home/vineet/GSoC/New/Test   -> getcwd()
/home/vineet/GSoC/New/Test  -> PWD
/home/vineet/GSoC/New  -> getcwd()
/home/vineet/GSoC/New/Test  -> PWD

Platform:

Since there is no shell in windows, the variable $PWD cannot be used in windows. It can only be used on linux. But for getcwd(), there is a similar command ‘_getcwd()’. So, getcwd() is platform independent.

Conclusion:

To be fair, both are important. But, for a generic purpose ‘getcwd()’ is appropriate. But to handle symlinks, ‘$PWD’ is needed. And also ‘$PWD’ gives wrong path when chdir() is used. So, maybe it is beneficial to have different implementations one that can handle symlinks and one that doesn`t. But, overall “getcwd()” is a better option.

References:

  1. https://github.com/mikeizbicki/ucr-cs100/issues/1088
  2. https://www.gnu.org/software/libc/manual/html_node/Working-Directory.html
  3. https://msdn.microsoft.com/en-us/library/sf98bd4y.aspx
  4. https://askubuntu.com/questions/476572/difference-in-use-between-pwd-and-pwd
  5. http://stackoverflow.com/questions/4362643/whats-the-difference-between-unix-built-in-pwd-command-and-its-pwd-environm
  6. https://unix.stackexchange.com/questions/174990/what-is-pwd-vs-current-working-directory
  7. https://askubuntu.com/questions/600714/creating-a-symlink-from-one-folder-to-another-with-different-names
  8. http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
  9. http://stackoverflow.com/questions/1951742/how-to-symlink-a-file-in-linux

Feel free to write a comment or give a suggestion.

One thought on “$PWD vs getcwd()

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s