Як один атомно змінює симпосилання на каталог у зайнятому полі?


18

Я намагаюся (якомога ближче) атомно змінити симпосилання. Я спробував:

ln -sf other_dir existing_symlink

Це просто помістило нове посилання в каталог, на який вказував існуючий_симпосилання.

ln -sf other_dir new_symlink
mv -f new_symlink existing_symlink

Це зробило те ж саме: він перемістив симпосилання в каталог.

cp -s other_dir existing_symlink

Він відмовляється, тому що це каталог.

Я читав, що mv -Tзроблено для цього, але -Tпрапорця не має прапора.

Відповіді:


1

Я не бачу, як можна отримати атомну операцію. Сторінка man для сайту symlink(2)каже, що вона дає, EEXISTякщо мета вже існує. Якщо ядро ​​не підтримує атомну операцію, обмеження у вашій країні користувача не мають значення.

Я також не бачу, як mv -Tдопомагає, навіть якщо у вас є. Спробуйте це у звичайній скриньці для Linux, з GNU mv:

$ mkdir a b
$ ln -s a z
$ mv -T b z
mv: cannot overwrite non-directory `z' with directory `b'

Я думаю, вам доведеться зробити це в два етапи: видаліть старе символьне посилання та відтворіть його.


1
Дійсно, на жаль, немає можливості змінити символічне атомно. Найкраще ви можете зняти старе посилання та створити нове. GNU coreutils має можливість зробити це за допомогою однієї команди ( ln -snf), але все ще є два системні виклики під кришкою.
Жил "ТАК - перестань бути злим"

43

Це може дійсно бути зроблено атомарному з rename(2), спочатку створити нову символічну посилання під тимчасовим ім'ям , а потім акуратно перезаписувати старий симлінк на одному диханні. Як зазначено на сторінці чоловіка :

Якщо newpath посилається на символічне посилання, посилання буде перезаписано.

У оболонці ви зробите це mv -Tнаступним чином:

$ mkdir a b
$ ln -s a z
$ ln -s b z.new
$ mv -T z.new z

Ви можете straceвиконати цю останню команду, щоб переконатися, що вона справді використовується rename(2)під кришкою:

$ strace mv -T z.new z
lstat64("z.new", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
lstat64("z", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
rename("z.new", "z")                    = 0

Зауважимо, що у вищесказаному і те, mv -Tі інше straceє Linux.

У FreeBSD використовуйте по mv -hчерзі.


1
Дуже хороша! Може бути корисним сказати, що в кінці ви маєте посилання від z до b!
Вінченцо Пій

Для рішення, незалежного від ОС, використовуйте мову сценаріїв, яка здатна використовувати renamesyscall безпосередньо замість mv -hабо mv -T. Наприклад, з Perl:perl -e 'rename "z.new", "z" or die $!'
Славен Резіч

8

Підбираючи там, де Arto зупинився тут, це цілком можливо, навіть без цього mv -T, вам просто потрібно створити нове символьне посилання з тим самим іменем, що і цільовий каталог, і mvце в батьківський каталог вашої цілі:

mkdir -p tmp/real_dir1 tmp/real_dir2
touch tmp/real_dir1/a tmp/real_dir2/a
# start with ./target_dir pointing to tmp/real_dir1
ln -s tmp/real_dir1 target_dir
# create a symlink named target_dir in tmp, pointing to real_dir2
ln -sf tmp/real_dir2 tmp/target_dir
# atomically mv it into ./ replacing ./target_dir
mv tmp/target_dir ./

Приклад коду, взятий за допомогою ( http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/ )


3

Ви пробували ln -snf?

Опція -nзамінює призначення, а не пише під ним, коли призначення є символьним посиланням на каталог.

Ура


3
ln -snfне є атомним: він від’єднує місце призначення, потім створює потрібне символьне посилання.
Жил "ТАК - перестань бути злим"

2
Зважаючи на те, що ОП була зацікавлена ​​в тому, щоб "наблизитись до можливості [e]" до атомної зміни симпосилання, це абсолютно розумна відповідь. Якщо є кращий, який може наблизитись (або бути) атомним, це можна прийняти. Я не думаю, що в цьому є необхідність.
Вілько
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.