1 |
Am 22.07.2012 17:21, schrieb Alan McKinnon: |
2 |
> On Sun, 22 Jul 2012 10:59:46 -0400 |
3 |
> Michael Mol <mikemol@×××××.com> wrote: |
4 |
> |
5 |
>> On Sun, Jul 22, 2012 at 9:53 AM, Florian Philipp |
6 |
>> <lists@×××××××××××.net> wrote: |
7 |
>>> Hi list! |
8 |
>>> |
9 |
>>> This is more a general POSIX question but I guess here I have the |
10 |
>>> best chance to get a definite answer. |
11 |
>>> |
12 |
>>> If I want to replace a file with another file without removing the |
13 |
>>> first one and without having a moment in time at which the file |
14 |
>>> name does not exist, I can use the following sequence: |
15 |
>>> |
16 |
>>> # swap $file1 with $file2 on the same file system |
17 |
>>> dir=$(dirname "$file1") |
18 |
>>> tmp=$(mktemp -u -d "$dir") # [1] |
19 |
>>> ln "$file1" "$tmp" |
20 |
>>> mv "$file2" "$file1" |
21 |
>>> mv "$tmp" "$file2" |
22 |
>>> |
23 |
>>> This works because mv does not affect the hardlink to $file1 and a |
24 |
>>> rename operation on a single file system is atomic. This is a handy |
25 |
>>> procedure when you have a background process which occasionally |
26 |
>>> opens $file1 and you don't want it to fail just because of bad |
27 |
>>> timing. |
28 |
>>> |
29 |
>>> Now my question is: How can I do a similar thing for a directory? I |
30 |
>>> cannot usually create hardlinks on directories (are there file |
31 |
>>> systems where this actually works?) and I cannot use mv to |
32 |
>>> overwrite one directory with another. |
33 |
>>> |
34 |
>>> The only idea I currently have is to create a level of indirection |
35 |
>>> via symlinks and then atomically overwrite the symlink. Is there |
36 |
>>> any other way? |
37 |
>> |
38 |
>> I'd be very, very wary of doing something like this without knowing |
39 |
>> exactly what programs might be accessing files inside the folder |
40 |
>> you're swapping out. In order to avoid a race where some poor process |
41 |
>> winds up with open file handles to some content in both your old and |
42 |
>> new folders, you'd really need a way to: |
43 |
>> |
44 |
>> 1) lock the folder so no programs can gain new handles on it or any |
45 |
>> file or folder inside |
46 |
>> 2) wait until all other open file handles to the folder and its |
47 |
>> contents are closed |
48 |
>> 3) swap out the folder |
49 |
>> 4) unlock |
50 |
>> |
51 |
>> (1) might be doable with flock() on a parent directory. |
52 |
>> (2) you'll need to use fuser to find the processes which have open |
53 |
>> handles and get them to release them. |
54 |
>> (3) mv a a_tmp; mv b a; mv a_tmp b |
55 |
>> (4) flock -u |
56 |
>> |
57 |
> |
58 |
> |
59 |
> I'd argue that what the OP wants is fundamentally impossible - there is |
60 |
> no such thing to my knowledge as a directory locking mechanism that is |
61 |
> guaranteed to always work in all cases - it would have to be |
62 |
> kernel-based to do that and I've personally never heard of such a |
63 |
> mechanism. |
64 |
> |
65 |
> The fact is, that directory operations are not atomic wrt the directory |
66 |
> contents, and the OP needs to find a different way to solve his problem. |
67 |
> |
68 |
> As for the OPs question re: hard-linking directories, Linux never allows |
69 |
> this as a user action - it can cause un-solveable loops when traversing |
70 |
> directory trees. Most other Unixes have the same rule for the same |
71 |
> reason. Some do allow it; but I forget which ones and I'm too lazy on a |
72 |
> Sunday afternoon to Google it :-) |
73 |
> |
74 |
> The kernel is of course perfectly able to hard-link directories - it |
75 |
> has to to be able to create . and .. at all, but that code only runs as |
76 |
> part of what mkdir does. In all other cases the kernel is hard-coded to |
77 |
> just refuse to do it. |
78 |
> |
79 |
|
80 |
Good points. Thanks, Michael, and Alan! |
81 |
|
82 |
I guess my approach would only work when the application consistently |
83 |
used openat() and friends instead of open(). Similarly, Michael's |
84 |
approach only works when the application honors advisory locks. |
85 |
|
86 |
I guess I can live with that and add both to my toolbox for cases where |
87 |
I can guarantee one or the other. |
88 |
|
89 |
Regards, |
90 |
Florian Philipp |