1 |
On Sun, Jul 22, 2012 at 9:53 AM, Florian Philipp <lists@×××××××××××.net> wrote: |
2 |
> Hi list! |
3 |
> |
4 |
> This is more a general POSIX question but I guess here I have the best |
5 |
> chance to get a definite answer. |
6 |
> |
7 |
> If I want to replace a file with another file without removing the first |
8 |
> one and without having a moment in time at which the file name does not |
9 |
> exist, I can use the following sequence: |
10 |
> |
11 |
> # swap $file1 with $file2 on the same file system |
12 |
> dir=$(dirname "$file1") |
13 |
> tmp=$(mktemp -u -d "$dir") # [1] |
14 |
> ln "$file1" "$tmp" |
15 |
> mv "$file2" "$file1" |
16 |
> mv "$tmp" "$file2" |
17 |
> |
18 |
> This works because mv does not affect the hardlink to $file1 and a |
19 |
> rename operation on a single file system is atomic. This is a handy |
20 |
> procedure when you have a background process which occasionally opens |
21 |
> $file1 and you don't want it to fail just because of bad timing. |
22 |
> |
23 |
> Now my question is: How can I do a similar thing for a directory? I |
24 |
> cannot usually create hardlinks on directories (are there file systems |
25 |
> where this actually works?) and I cannot use mv to overwrite one |
26 |
> directory with another. |
27 |
> |
28 |
> The only idea I currently have is to create a level of indirection via |
29 |
> symlinks and then atomically overwrite the symlink. Is there any other way? |
30 |
|
31 |
I'd be very, very wary of doing something like this without knowing |
32 |
exactly what programs might be accessing files inside the folder |
33 |
you're swapping out. In order to avoid a race where some poor process |
34 |
winds up with open file handles to some content in both your old and |
35 |
new folders, you'd really need a way to: |
36 |
|
37 |
1) lock the folder so no programs can gain new handles on it or any |
38 |
file or folder inside |
39 |
2) wait until all other open file handles to the folder and its |
40 |
contents are closed |
41 |
3) swap out the folder |
42 |
4) unlock |
43 |
|
44 |
(1) might be doable with flock() on a parent directory. |
45 |
(2) you'll need to use fuser to find the processes which have open |
46 |
handles and get them to release them. |
47 |
(3) mv a a_tmp; mv b a; mv a_tmp b |
48 |
(4) flock -u |
49 |
|
50 |
-- |
51 |
:wq |