Weird behavior while moving a directory - Servers Administration, Networking, & Virtualization
Users browsing this thread: 2 Guest(s)
|
|||
Hello fellow nixers,
In this thread I'll describe a behavior I've noticed by mistake. Maybe someone can enlighten me about it. Here's the scenario: Try to follow with me. We have two users, user1 and user2. user1 creates a directory, and check it's stats: Code: ~ > mkdir will_disappear Code: ~/will_disappear > touch will_disappear/magic Now user2 enters the directory... Code: ~/will_disappear > cd will_disappear Code: ~ > mv will_disappear{,.bak} The inode of the directory hasn't changed but the inode of the parent directory has, this makes sense. Clarifications: To user2 there doesn't seem to be any issue so far, he can't notice until he does something like this: Code: ~/will_disappear > touch $(pwd)/test Code: ~/will_disappear > pwd Here's my investigation: This is very weird, I first thought that the shell might be highjacking the `pwd` command and I wanted to make sure. With user2 I ran: Code: ~/will_disappear > strace pwd < Quote:getcwd("/home/patrick/will_disappear.bak", 4096) = 33It's doing the system call correctly and even writing on the screen the right current directory. Now why do I see wrong results, I'm not sure... I did the test with bash and zsh so it might not be shell dependent. The behavior is more or less the same when user1 removes the directory user2 is in. I think I've found the answer: Code: ~/will_disappear > which pwd Lesson, alway use the absolute path for your commands, don't trust the shell. Some info on pwd More info on inode More info on virtual filesystem What do you think? |
|||
|
|||
One also has to keep in mind that if user2 moves the directory to a new disk, user1 can not do anything in this directory.
Read also about this (from wikipedia): Quote:A file's inode number stays the same when it is moved to another directory on the same device, or when the disk is defragmented which may change its physical location. This also implies that completely conforming inode behavior is impossible to implement with many non-Unix file systems, such as FAT and its descendants, which don't have a way of storing this invariance when both a file's directory entry and its data are moved around. Now if we have a FAT fs mounted and someone was to rename it, it might cause other links to break and/or the user currently being in it to not be able to access it anymore. |
|||
|
|||
Nice question, I love little riddles like this. :-)
So, the point is, Bash itself is holding a reference to the current working directory -- but that reference is a string. Let's have a look at Bash's source code. "builtins/cd.def": Both "cd" and "pwd" are defined here. IIUC, the function pwd_builtin() is what's being executed when you type "pwd". It uses a shortcut: Code: #define tcwd the_current_working_directory It uses the value of "the_current_working_directory", if set. Aha. Below that, there's this piece of code: Code: /* Try again using getcwd() if canonicalization fails (for instance, if So, Bash tries to detect whether its current value of "tcwd" is still valid. It uses same_file() to do that, defined in "general.c". This checks whether "." and "tcwd" point to the same inode on the same device. Yes, of course they do. But that doesn't mean that the cwd's directory name is still valid! -- edit: No, wait, I'm confused. "tcwd" is the old directory name, it's invalid. But strace shows that there are no calls to stat() anyway, so I'd assume the code doesn't even execute the call to same_file(). Probably because posixly_correct is not set. Yeah, if I start a Bash with "POSIXLY_CORRECT=1 bash", then "pwd" shows the new directory name (and I see calls to stat() in strace). This is indeed weird. Why not just call the syscall getcwd() and be done with it? Why the hazzle with holding a string (!) reference to the cwd? I suspect this is for historical reasons ... |
|||
|
|||
(30-09-2016, 09:59 AM)vain Wrote: This is indeed weird. Why not just call the syscall getcwd() and be done with it? Why the hazzle with holding a string (!) reference to the cwd? I suspect this is for historical reasons ...Probably a mean of caching. Also, where is the environment variable PWD mentioned in the source, when you are at it. PWD holds the current directory and is used by many shells. Is it set on change but not used or is it actually used and the environment variables are the "database" of those shells? |
|||
|
|||
(30-09-2016, 10:20 AM)venam Wrote: the environment variables are the "database" of those shells It would appear that, sometimes, this is indeed the case. For example, in eval.c of Bash: Code: /* Send an escape sequence to emacs term mode to tell it the Or jobs.c: Code: /* Return the working directory for the current process. Unlike Funny thing is, I don't see $PWD being used in the "pwd" shell builtin. Instead, it calls get_working_directory() as mentioned in my previous post, which, in turn, calls the syscall getcwd(). In German, there's the nice expression, "das ist organisch gewachsen" (literal translation something like "grown in an organic manner"), which basically is a euphemism for "this is a very old code base and 1000 people have hacked on it and nobody ever cared to refactor things". :-) |
|||
|
|||
You mean "Das ist historisch gewachsen." or?
|
|||
|
|||
That might be more correct, yes. I think we use both phrases at work. %)
|
|||