1818
1919import java .io .File ;
2020import java .io .IOException ;
21+ import java .io .UncheckedIOException ;
2122import java .nio .file .FileSystem ;
2223import java .nio .file .Files ;
24+ import java .nio .file .LinkOption ;
2325import java .nio .file .Path ;
2426import java .nio .file .Paths ;
2527import java .nio .file .attribute .FileAttribute ;
28+ import java .nio .file .attribute .PosixFileAttributes ;
2629import java .nio .file .attribute .PosixFilePermission ;
2730import java .nio .file .attribute .PosixFilePermissions ;
31+ import java .nio .file .attribute .UserPrincipal ;
2832import java .security .MessageDigest ;
2933import java .util .EnumSet ;
3034import java .util .HexFormat ;
@@ -56,6 +60,8 @@ public class ApplicationTemp {
5660
5761 private final Lock pathLock = new ReentrantLock ();
5862
63+ private final @ Nullable UserPrincipal directoryOwner ;
64+
5965 private volatile @ Nullable Path path ;
6066
6167 /**
@@ -71,6 +77,22 @@ public ApplicationTemp() {
7177 */
7278 public ApplicationTemp (@ Nullable Class <?> sourceClass ) {
7379 this .sourceClass = sourceClass ;
80+ this .directoryOwner = directoryOwner ();
81+ }
82+
83+ private static @ Nullable UserPrincipal directoryOwner () {
84+ try {
85+ Path tempFile = Files .createTempFile ("application-temp" , "-owner" );
86+ UserPrincipal owner = Files .getOwner (tempFile );
87+ Files .delete (tempFile );
88+ return owner ;
89+ }
90+ catch (UnsupportedOperationException ex ) {
91+ return null ;
92+ }
93+ catch (IOException ex ) {
94+ throw new UncheckedIOException (ex );
95+ }
7496 }
7597
7698 @ Override
@@ -115,8 +137,28 @@ private Path getPath() {
115137
116138 private Path createDirectory (Path path ) {
117139 try {
118- if (!Files .exists (path )) {
119- Files .createDirectory (path , getFileAttributes (path .getFileSystem (), DIRECTORY_PERMISSIONS ));
140+ FileSystem fileSystem = path .getFileSystem ();
141+ if (!Files .exists (path , LinkOption .NOFOLLOW_LINKS )) {
142+ Files .createDirectory (path , asFileAttributes (fileSystem , DIRECTORY_PERMISSIONS ));
143+ }
144+ else {
145+ if (supportsPosixView (fileSystem )) {
146+ PosixFileAttributes attributes = Files .readAttributes (path , PosixFileAttributes .class ,
147+ LinkOption .NOFOLLOW_LINKS );
148+ Assert .state (attributes .isDirectory (),
149+ () -> "'" + path + "' already exists but it is not a directory" );
150+ Assert .state (DIRECTORY_PERMISSIONS .equals (attributes .permissions ()), () -> "Existing directory '"
151+ + path + "' does not have the permissions " + DIRECTORY_PERMISSIONS );
152+ assertDirectoryOwnership (attributes .owner (), path );
153+ }
154+ else {
155+ try {
156+ assertDirectoryOwnership (Files .getOwner (path , LinkOption .NOFOLLOW_LINKS ), path );
157+ }
158+ catch (UnsupportedOperationException ex ) {
159+ // Ownership check not supported. Continue.
160+ }
161+ }
120162 }
121163 return path ;
122164 }
@@ -125,13 +167,24 @@ private Path createDirectory(Path path) {
125167 }
126168 }
127169
128- private FileAttribute <?>[] getFileAttributes (FileSystem fileSystem , EnumSet <PosixFilePermission > ownerReadWrite ) {
129- if (!fileSystem .supportedFileAttributeViews ().contains ("posix" )) {
170+ private void assertDirectoryOwnership (UserPrincipal owner , Path path ) {
171+ if (this .directoryOwner != null ) {
172+ Assert .state (this .directoryOwner .equals (owner ),
173+ () -> "Existing directory '" + path + "' is not owned by " + this .directoryOwner .getName ());
174+ }
175+ }
176+
177+ private FileAttribute <?>[] asFileAttributes (FileSystem fileSystem , EnumSet <PosixFilePermission > ownerReadWrite ) {
178+ if (!supportsPosixView (fileSystem )) {
130179 return NO_FILE_ATTRIBUTES ;
131180 }
132181 return new FileAttribute <?>[] { PosixFilePermissions .asFileAttribute (ownerReadWrite ) };
133182 }
134183
184+ private boolean supportsPosixView (FileSystem fileSystem ) {
185+ return fileSystem .supportedFileAttributeViews ().contains ("posix" );
186+ }
187+
135188 private Path getTempDirectory () {
136189 String property = System .getProperty ("java.io.tmpdir" );
137190 Assert .state (StringUtils .hasLength (property ), "No 'java.io.tmpdir' property set" );
0 commit comments