Package: coreutils;
Reported by: Mirsad Goran Todorovac <mtodorov3_69 <at> yahoo.com>
Date: Mon, 2 Jan 2017 23:12:01 UTC
Severity: wishlist
View this message in rfc822 format
From: Mirsad Goran Todorovac <mtodorov3_69 <at> yahoo.com> To: Paul Eggert <eggert <at> cs.ucla.edu>, "25342 <at> debbugs.gnu.org" <25342 <at> debbugs.gnu.org> Subject: bug#25342: GNU coreutils: race condition in "ln -f source dest" Date: Thu, 5 Jan 2017 09:30:42 +0000 (UTC)
[Message part 1 (text/plain, inline)]
P.S. Obvious advantage is that unlink ("dest") is not required if it exists, thus we offer a workaround for race condition.In first example: # ln -f /etc/resolv.conf.new /etc/resolv.conf there was a time period between unlink ("/etc/resolv.conf"); andlinkat (AT_CDWFD, "/etc/resolv.conf.new", AT_CWDFD, "/etc/resolv.conf", logical ? AT_SYMLINK_FOLLOW : 0); between these two syscalls process or thread may be preempted and other process (like browser) could fail in gethostbyname().This is just one example. I will torment you no longer. Thank you for your patience Sir if you've read thus far. God bless! little brother Mirsad On Thursday, January 5, 2017 10:24 AM, Mirsad Goran Todorovac <mtodorov3_69 <at> yahoo.com> wrote: The trace above should do a ln -b -f src dest, linking (hard linking to existing file providing a backup in "dest~", without at suffix and stuff, which is not important for the story): EXAMPLE WITH BACKUP: ln -b -f src dest initially we have: "src" -> inode1 "dest" -> inode2 link ("dest", "dest~"); now: "src" -> inode1 "dest" -> inode2 "dest~" -> inode2 link ("src", "src.######.bak"); now: "src" -> inode1 "src.######.bak" -> inode1 "dest" -> inode2 "dest~" -> inode2 rename ("src.######.bak", "dest"); finally: "src" -> inode1 "dest" -> inode1 "dest~" -> inode2 Result is that "new" is backed up in "new~" "simulaneously", that is in single command while hard link "old" overwrites hard link "new". The -b (backup) is optional, in which case we have only black parts, as follows: WITHOUT BACKUP: ln -f src dest initially we have: "src" -> inode1 "dest" -> inode2 link ("src", "src.######.bak"); now: "src" -> inode1 "src.######.bak" -> inode1 "src" -> inode2rename ("src.######.bak", "dest"); finally: "src" -> inode1 "dest" -> inode1 Where initial content of file "dest" was lost.Of course, it would be much better if linkat() had additional flag: int linkat (AT_CWDFD, "source", AT_CWDFD, "dest", AT_SYMLINK_FOLLOW | AT_FORCE_OVERWRITE); but as you have correctly said, we cannot influence POSIX and Linux kernel makers. Sorry if I took too much of your time. Thank Heavens for such good and logical design of UN*X filesystems. Regards and All the best,M.T. _______________________________________________________________________________________ On Thursday, January 5, 2017 9:50 AM, Mirsad Goran Todorovac <mtodorov3_69 <at> yahoo.com> wrote: Pity, 'cause it works for me with a small workaround:link("copy2", "copy2~") = 0 getpid() = 3085 linkat(AT_FDCWD, "copy", AT_FDCWD, "copy.003085.bak", 0) = 0 renameat(AT_FDCWD, "copy.003085.bak", AT_FDCWD, "copy2") = 0 I did not exactly understand? What else can be moved, if not two hard links?Directory entry can be one of pointer to inode (file, directory or less likely something else), or pointer to another directory entry (symbolic link), ain't that right? Can you please provide me with a reference of such behavior of renameat()? I realized just now that you want to make your code universal and protable.On Ubuntu Linux it works for me. marvin <at> marvin-desktop:~$ uname -a Linux marvin-desktop 3.5.0-34-generic #55-Ubuntu SMP Thu Jun 6 20:20:19 UTC 2013 i686 athlon i686 GNU/Linux marvin <at> marvin-desktop:~$ dpkg -l | egrep 'libc6' ii libc6:i386 2.23-0ubuntu5 i386 GNU C If you can provide me with a reference, I'll try to understand renameat() problem. Best of luck in New Year,M.T. On Thursday, January 5, 2017 8:57 AM, Paul Eggert <eggert <at> cs.ucla.edu> wrote: Mirsad Goran Todorovac wrote: > Please consider the trace below. As I don't know what you're tracing, I don't know what to consider. But really, the basic idea is simple: renameat mishandles the case where old and new names are already hard links, and any code based on renameat needs to work around this problem. (We can't easily change renameat's behavior, as the behavior is required by POSIX.)
[Message part 2 (text/html, inline)]
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.