Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

FS_POSIX.java 15KB

Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
Fix atomic lock file creation on NFS FS_POSIX.createNewFile(File) failed to properly implement atomic file creation on NFS using the algorithm [1]: - name of the hard link must be unique to prevent that two processes using different NFS clients try to create the same link. This would render nlink useless to detect if there was a race. - the hard link must be retained for the lifetime of the file since we don't know when the state of the involved NFS clients will be synchronized. This depends on NFS configuration options. To fix these issues we need to change the signature of createNewFile which would break API. Hence deprecate the old method FS.createNewFile(File) and add a new method createNewFileAtomic(File). The new method returns a LockToken which needs to be retained by the caller (LockFile) until all involved NFS clients synchronized their state. Since we don't know when the NFS caches are synchronized we need to retain the token until the corresponding file is no longer needed. The LockToken must be closed after the LockFile using it has been committed or unlocked. On Posix, if core.supportsAtomicCreateNewFile = false this will delete the hard link which guarded the atomic creation of the file. When acquiring the lock fails ensure that the hard link is removed. [1] https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html also see file creation flag O_EXCL in http://man7.org/linux/man-pages/man2/open.2.html Change-Id: I84fcb16143a5f877e9b08c6ee0ff8fa4ea68a90d Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
5 år sedan
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. /*
  2. * Copyright (C) 2010, Robin Rosenberg
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.util;
  44. import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION;
  45. import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_SUPPORTSATOMICFILECREATION;
  46. import java.io.BufferedReader;
  47. import java.io.File;
  48. import java.io.IOException;
  49. import java.io.InputStreamReader;
  50. import java.io.PrintStream;
  51. import java.nio.charset.Charset;
  52. import java.nio.file.FileAlreadyExistsException;
  53. import java.nio.file.FileStore;
  54. import java.nio.file.FileSystemException;
  55. import java.nio.file.Files;
  56. import java.nio.file.InvalidPathException;
  57. import java.nio.file.Path;
  58. import java.nio.file.Paths;
  59. import java.nio.file.attribute.PosixFilePermission;
  60. import java.text.MessageFormat;
  61. import java.util.ArrayList;
  62. import java.util.Arrays;
  63. import java.util.List;
  64. import java.util.Map;
  65. import java.util.Optional;
  66. import java.util.Set;
  67. import java.util.UUID;
  68. import java.util.concurrent.ConcurrentHashMap;
  69. import org.eclipse.jgit.annotations.Nullable;
  70. import org.eclipse.jgit.api.errors.JGitInternalException;
  71. import org.eclipse.jgit.errors.CommandFailedException;
  72. import org.eclipse.jgit.errors.ConfigInvalidException;
  73. import org.eclipse.jgit.internal.JGitText;
  74. import org.eclipse.jgit.lib.Constants;
  75. import org.eclipse.jgit.lib.Repository;
  76. import org.eclipse.jgit.lib.StoredConfig;
  77. import org.slf4j.Logger;
  78. import org.slf4j.LoggerFactory;
  79. /**
  80. * Base FS for POSIX based systems
  81. *
  82. * @since 3.0
  83. */
  84. public class FS_POSIX extends FS {
  85. private final static Logger LOG = LoggerFactory.getLogger(FS_POSIX.class);
  86. private static final int DEFAULT_UMASK = 0022;
  87. private volatile int umask = -1;
  88. private static final Map<FileStore, Boolean> CAN_HARD_LINK = new ConcurrentHashMap<>();
  89. private volatile AtomicFileCreation supportsAtomicFileCreation = AtomicFileCreation.UNDEFINED;
  90. private enum AtomicFileCreation {
  91. SUPPORTED, NOT_SUPPORTED, UNDEFINED
  92. }
  93. /**
  94. * Default constructor.
  95. */
  96. protected FS_POSIX() {
  97. }
  98. /**
  99. * Constructor
  100. *
  101. * @param src
  102. * FS to copy some settings from
  103. */
  104. protected FS_POSIX(FS src) {
  105. super(src);
  106. if (src instanceof FS_POSIX) {
  107. umask = ((FS_POSIX) src).umask;
  108. }
  109. }
  110. /** {@inheritDoc} */
  111. @Override
  112. public FS newInstance() {
  113. return new FS_POSIX(this);
  114. }
  115. /**
  116. * Set the umask, overriding any value observed from the shell.
  117. *
  118. * @param umask
  119. * mask to apply when creating files.
  120. * @since 4.0
  121. */
  122. public void setUmask(int umask) {
  123. this.umask = umask;
  124. }
  125. private int umask() {
  126. int u = umask;
  127. if (u == -1) {
  128. u = readUmask();
  129. umask = u;
  130. }
  131. return u;
  132. }
  133. /** @return mask returned from running {@code umask} command in shell. */
  134. private static int readUmask() {
  135. try {
  136. Process p = Runtime.getRuntime().exec(
  137. new String[] { "sh", "-c", "umask" }, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  138. null, null);
  139. try (BufferedReader lineRead = new BufferedReader(
  140. new InputStreamReader(p.getInputStream(), Charset
  141. .defaultCharset().name()))) {
  142. if (p.waitFor() == 0) {
  143. String s = lineRead.readLine();
  144. if (s != null && s.matches("0?\\d{3}")) { //$NON-NLS-1$
  145. return Integer.parseInt(s, 8);
  146. }
  147. }
  148. return DEFAULT_UMASK;
  149. }
  150. } catch (Exception e) {
  151. return DEFAULT_UMASK;
  152. }
  153. }
  154. /** {@inheritDoc} */
  155. @Override
  156. protected File discoverGitExe() {
  157. String path = SystemReader.getInstance().getenv("PATH"); //$NON-NLS-1$
  158. File gitExe = searchPath(path, "git"); //$NON-NLS-1$
  159. if (gitExe == null) {
  160. if (SystemReader.getInstance().isMacOS()) {
  161. if (searchPath(path, "bash") != null) { //$NON-NLS-1$
  162. // On MacOSX, PATH is shorter when Eclipse is launched from the
  163. // Finder than from a terminal. Therefore try to launch bash as a
  164. // login shell and search using that.
  165. String w;
  166. try {
  167. w = readPipe(userHome(),
  168. new String[]{"bash", "--login", "-c", "which git"}, // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
  169. Charset.defaultCharset().name());
  170. } catch (CommandFailedException e) {
  171. LOG.warn(e.getMessage());
  172. return null;
  173. }
  174. if (!StringUtils.isEmptyOrNull(w)) {
  175. gitExe = new File(w);
  176. }
  177. }
  178. }
  179. }
  180. return gitExe;
  181. }
  182. /** {@inheritDoc} */
  183. @Override
  184. public boolean isCaseSensitive() {
  185. return !SystemReader.getInstance().isMacOS();
  186. }
  187. /** {@inheritDoc} */
  188. @Override
  189. public boolean supportsExecute() {
  190. return true;
  191. }
  192. /** {@inheritDoc} */
  193. @Override
  194. public boolean canExecute(File f) {
  195. return FileUtils.canExecute(f);
  196. }
  197. /** {@inheritDoc} */
  198. @Override
  199. public boolean setExecute(File f, boolean canExecute) {
  200. if (!isFile(f))
  201. return false;
  202. if (!canExecute)
  203. return f.setExecutable(false, false);
  204. try {
  205. Path path = FileUtils.toPath(f);
  206. Set<PosixFilePermission> pset = Files.getPosixFilePermissions(path);
  207. // owner (user) is always allowed to execute.
  208. pset.add(PosixFilePermission.OWNER_EXECUTE);
  209. int mask = umask();
  210. apply(pset, mask, PosixFilePermission.GROUP_EXECUTE, 1 << 3);
  211. apply(pset, mask, PosixFilePermission.OTHERS_EXECUTE, 1);
  212. Files.setPosixFilePermissions(path, pset);
  213. return true;
  214. } catch (IOException e) {
  215. // The interface doesn't allow to throw IOException
  216. final boolean debug = Boolean.parseBoolean(SystemReader
  217. .getInstance().getProperty("jgit.fs.debug")); //$NON-NLS-1$
  218. if (debug)
  219. System.err.println(e);
  220. return false;
  221. }
  222. }
  223. private static void apply(Set<PosixFilePermission> set,
  224. int umask, PosixFilePermission perm, int test) {
  225. if ((umask & test) == 0) {
  226. // If bit is clear in umask, permission is allowed.
  227. set.add(perm);
  228. } else {
  229. // If bit is set in umask, permission is denied.
  230. set.remove(perm);
  231. }
  232. }
  233. /** {@inheritDoc} */
  234. @Override
  235. public ProcessBuilder runInShell(String cmd, String[] args) {
  236. List<String> argv = new ArrayList<>(4 + args.length);
  237. argv.add("sh"); //$NON-NLS-1$
  238. argv.add("-c"); //$NON-NLS-1$
  239. argv.add(cmd + " \"$@\""); //$NON-NLS-1$
  240. argv.add(cmd);
  241. argv.addAll(Arrays.asList(args));
  242. ProcessBuilder proc = new ProcessBuilder();
  243. proc.command(argv);
  244. return proc;
  245. }
  246. /** {@inheritDoc} */
  247. @Override
  248. public ProcessResult runHookIfPresent(Repository repository, String hookName,
  249. String[] args, PrintStream outRedirect, PrintStream errRedirect,
  250. String stdinArgs) throws JGitInternalException {
  251. return internalRunHookIfPresent(repository, hookName, args, outRedirect,
  252. errRedirect, stdinArgs);
  253. }
  254. /** {@inheritDoc} */
  255. @Override
  256. public boolean retryFailedLockFileCommit() {
  257. return false;
  258. }
  259. /** {@inheritDoc} */
  260. @Override
  261. public boolean supportsSymlinks() {
  262. return true;
  263. }
  264. /** {@inheritDoc} */
  265. @Override
  266. public void setHidden(File path, boolean hidden) throws IOException {
  267. // no action on POSIX
  268. }
  269. /** {@inheritDoc} */
  270. @Override
  271. public Attributes getAttributes(File path) {
  272. return FileUtils.getFileAttributesPosix(this, path);
  273. }
  274. /** {@inheritDoc} */
  275. @Override
  276. public File normalize(File file) {
  277. return FileUtils.normalize(file);
  278. }
  279. /** {@inheritDoc} */
  280. @Override
  281. public String normalize(String name) {
  282. return FileUtils.normalize(name);
  283. }
  284. /** {@inheritDoc} */
  285. @Override
  286. public File findHook(Repository repository, String hookName) {
  287. final File gitdir = repository.getDirectory();
  288. if (gitdir == null) {
  289. return null;
  290. }
  291. final Path hookPath = gitdir.toPath().resolve(Constants.HOOKS)
  292. .resolve(hookName);
  293. if (Files.isExecutable(hookPath))
  294. return hookPath.toFile();
  295. return null;
  296. }
  297. /** {@inheritDoc} */
  298. @Override
  299. public boolean supportsAtomicCreateNewFile() {
  300. if (supportsAtomicFileCreation == AtomicFileCreation.UNDEFINED) {
  301. try {
  302. StoredConfig config = SystemReader.getInstance().getUserConfig();
  303. String value = config.getString(CONFIG_CORE_SECTION, null,
  304. CONFIG_KEY_SUPPORTSATOMICFILECREATION);
  305. if (value != null) {
  306. supportsAtomicFileCreation = StringUtils.toBoolean(value)
  307. ? AtomicFileCreation.SUPPORTED
  308. : AtomicFileCreation.NOT_SUPPORTED;
  309. } else {
  310. supportsAtomicFileCreation = AtomicFileCreation.SUPPORTED;
  311. }
  312. } catch (IOException | ConfigInvalidException e) {
  313. LOG.warn(JGitText.get().assumeAtomicCreateNewFile, e);
  314. supportsAtomicFileCreation = AtomicFileCreation.SUPPORTED;
  315. }
  316. }
  317. return supportsAtomicFileCreation == AtomicFileCreation.SUPPORTED;
  318. }
  319. @Override
  320. @SuppressWarnings("boxing")
  321. /**
  322. * {@inheritDoc}
  323. * <p>
  324. * An implementation of the File#createNewFile() semantics which works also
  325. * on NFS. If the config option
  326. * {@code core.supportsAtomicCreateNewFile = true} (which is the default)
  327. * then simply File#createNewFile() is called.
  328. *
  329. * But if {@code core.supportsAtomicCreateNewFile = false} then after
  330. * successful creation of the lock file a hard link to that lock file is
  331. * created and the attribute nlink of the lock file is checked to be 2. If
  332. * multiple clients manage to create the same lock file nlink would be
  333. * greater than 2 showing the error.
  334. *
  335. * @see "https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html"
  336. *
  337. * @deprecated use {@link FS_POSIX#createNewFileAtomic(File)} instead
  338. * @since 4.5
  339. */
  340. @Deprecated
  341. public boolean createNewFile(File lock) throws IOException {
  342. if (!lock.createNewFile()) {
  343. return false;
  344. }
  345. if (supportsAtomicCreateNewFile()) {
  346. return true;
  347. }
  348. Path lockPath = lock.toPath();
  349. Path link = null;
  350. FileStore store = null;
  351. try {
  352. store = Files.getFileStore(lockPath);
  353. } catch (SecurityException e) {
  354. return true;
  355. }
  356. try {
  357. Boolean canLink = CAN_HARD_LINK.computeIfAbsent(store,
  358. s -> Boolean.TRUE);
  359. if (Boolean.FALSE.equals(canLink)) {
  360. return true;
  361. }
  362. link = Files.createLink(
  363. Paths.get(lock.getAbsolutePath() + ".lnk"), //$NON-NLS-1$
  364. lockPath);
  365. Integer nlink = (Integer) (Files.getAttribute(lockPath,
  366. "unix:nlink")); //$NON-NLS-1$
  367. if (nlink > 2) {
  368. LOG.warn(MessageFormat.format(
  369. JGitText.get().failedAtomicFileCreation, lockPath,
  370. nlink));
  371. return false;
  372. } else if (nlink < 2) {
  373. CAN_HARD_LINK.put(store, Boolean.FALSE);
  374. }
  375. return true;
  376. } catch (UnsupportedOperationException | IllegalArgumentException e) {
  377. CAN_HARD_LINK.put(store, Boolean.FALSE);
  378. return true;
  379. } finally {
  380. if (link != null) {
  381. Files.delete(link);
  382. }
  383. }
  384. }
  385. /**
  386. * {@inheritDoc}
  387. * <p>
  388. * An implementation of the File#createNewFile() semantics which can create
  389. * a unique file atomically also on NFS. If the config option
  390. * {@code core.supportsAtomicCreateNewFile = true} (which is the default)
  391. * then simply Files#createFile() is called.
  392. *
  393. * But if {@code core.supportsAtomicCreateNewFile = false} then after
  394. * successful creation of the lock file a hard link to that lock file is
  395. * created and the attribute nlink of the lock file is checked to be 2. If
  396. * multiple clients manage to create the same lock file nlink would be
  397. * greater than 2 showing the error. The hard link needs to be retained
  398. * until the corresponding file is no longer needed in order to prevent that
  399. * another process can create the same file concurrently using another NFS
  400. * client which might not yet see the file due to caching.
  401. *
  402. * @see "https://www.time-travellers.org/shane/papers/NFS_considered_harmful.html"
  403. * @param file
  404. * the unique file to be created atomically
  405. * @return LockToken this lock token must be held until the file is no
  406. * longer needed
  407. * @throws IOException
  408. * @since 5.0
  409. */
  410. @Override
  411. public LockToken createNewFileAtomic(File file) throws IOException {
  412. Path path;
  413. try {
  414. path = file.toPath();
  415. Files.createFile(path);
  416. } catch (FileAlreadyExistsException | InvalidPathException e) {
  417. return token(false, null);
  418. }
  419. if (supportsAtomicCreateNewFile()) {
  420. return token(true, null);
  421. }
  422. Path link = null;
  423. FileStore store = null;
  424. try {
  425. store = Files.getFileStore(path);
  426. } catch (SecurityException e) {
  427. return token(true, null);
  428. }
  429. try {
  430. Boolean canLink = CAN_HARD_LINK.computeIfAbsent(store,
  431. s -> Boolean.TRUE);
  432. if (Boolean.FALSE.equals(canLink)) {
  433. return token(true, null);
  434. }
  435. link = Files.createLink(Paths.get(uniqueLinkPath(file)), path);
  436. Integer nlink = (Integer) (Files.getAttribute(path,
  437. "unix:nlink")); //$NON-NLS-1$
  438. if (nlink.intValue() > 2) {
  439. LOG.warn(MessageFormat.format(
  440. JGitText.get().failedAtomicFileCreation, path, nlink));
  441. return token(false, link);
  442. } else if (nlink.intValue() < 2) {
  443. CAN_HARD_LINK.put(store, Boolean.FALSE);
  444. }
  445. return token(true, link);
  446. } catch (UnsupportedOperationException | IllegalArgumentException
  447. | FileSystemException | SecurityException e) {
  448. CAN_HARD_LINK.put(store, Boolean.FALSE);
  449. return token(true, link);
  450. }
  451. }
  452. private static LockToken token(boolean created, @Nullable Path p) {
  453. return ((p != null) && Files.exists(p))
  454. ? new LockToken(created, Optional.of(p))
  455. : new LockToken(created, Optional.empty());
  456. }
  457. private static String uniqueLinkPath(File file) {
  458. UUID id = UUID.randomUUID();
  459. return file.getAbsolutePath() + "." //$NON-NLS-1$
  460. + Long.toHexString(id.getMostSignificantBits())
  461. + Long.toHexString(id.getLeastSignificantBits());
  462. }
  463. }