Skip to content

Commit 01cd40b

Browse files
committed
Perms kinda working
1 parent 050f73f commit 01cd40b

9 files changed

Lines changed: 133 additions & 36 deletions

File tree

jsync-engine/src/main/java/com/fizzed/jsync/engine/JsyncEngine.java

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@
88
import java.io.InputStream;
99
import java.io.OutputStream;
1010
import java.nio.file.Path;
11-
import java.util.ArrayList;
12-
import java.util.Collections;
13-
import java.util.List;
14-
import java.util.Objects;
11+
import java.util.*;
1512

1613
import static java.util.Arrays.asList;
1714
import static java.util.stream.Collectors.toList;
@@ -26,6 +23,7 @@ public class JsyncEngine {
2623
private boolean force;
2724
private boolean parents;
2825
private boolean ignoreTimes;
26+
private boolean skipPermissions;
2927
private int maxFilesMaybeModifiedLimit;
3028
private List<String> excludes;
3129

@@ -35,6 +33,7 @@ public JsyncEngine() {
3533
this.force = false;
3634
this.parents = false;
3735
this.ignoreTimes = false;
36+
this.skipPermissions = false;
3837
this.preferredChecksums = new ArrayList<>(asList(Checksum.CK, Checksum.MD5));
3938
this.maxFilesMaybeModifiedLimit = 256;
4039
this.excludes = null;
@@ -86,6 +85,15 @@ public JsyncEngine setIgnoreTimes(boolean ignoreTimes) {
8685
return this;
8786
}
8887

88+
public boolean isSkipPermissions() {
89+
return skipPermissions;
90+
}
91+
92+
public JsyncEngine setSkipPermissions(boolean skipPermissions) {
93+
this.skipPermissions = skipPermissions;
94+
return this;
95+
}
96+
8997
public List<Checksum> getPreferredChecksums() {
9098
return this.preferredChecksums;
9199
}
@@ -280,7 +288,7 @@ protected void syncFile(JsyncResult result, List<VirtualPathPair> deferredFiles,
280288
if (log.isDebugEnabled()) log.debug("Verified file {} ({})", targetPath, changes);
281289
}
282290

283-
if (changes.isStatModified()) {
291+
if (changes.isStatModified(this.skipPermissions)) {
284292
// stat will need updated if the file is either new, updated, or if only the perms/times need updating
285293
this.updateStat(result, sourcePath, targetVfs, targetPath, changes, fileWasTransferred);
286294
}
@@ -434,7 +442,7 @@ protected void syncDirectory(int level, JsyncResult result, List<VirtualPath> ex
434442

435443
// last step is to update the stat of the target dir
436444
// To successfully preserve directory timestamps, you must set the directory attributes after you have finished touching every single file inside that directory.
437-
if (changes.isStatModified()) {
445+
if (changes.isStatModified(this.skipPermissions)) {
438446
// stat will need updated if the dir is new OR if the dir stats have changed
439447
this.updateStat(result, sourcePath, targetVfs, targetPath, changes, changes.isMissing());
440448
}
@@ -479,7 +487,7 @@ protected JsyncPathChanges detectChanges(VirtualPath sourcePath, VirtualPath tar
479487
timestamps = true;
480488
}
481489

482-
if (sourcePath.getStat().getPermissions() != targetPath.getStat().getPermissions()) {
490+
if (!this.skipPermissions && sourcePath.getStat().getPermissions() != targetPath.getStat().getPermissions()) {
483491
log.trace("Source path {} perms {} != target perms {}", sourcePath, sourcePath.getStat().getPermissions(), targetPath.getStat().getPermissions());
484492
permissions = true;
485493
}
@@ -540,7 +548,20 @@ protected void transferFile(JsyncResult result, VirtualFileSystem sourceVfs, Vir
540548
protected void updateStat(JsyncResult result, VirtualPath sourcePath, VirtualFileSystem targetVfs, VirtualPath targetPath, JsyncPathChanges changes, boolean associatedWithFileModifiedOrDirCreated) throws IOException {
541549
this.eventHandler.willUpdateStat(sourcePath, targetPath, changes, associatedWithFileModifiedOrDirCreated);
542550

543-
targetVfs.updateStat(targetPath, sourcePath.getStat());
551+
final Set<StatUpdateOption> options = EnumSet.noneOf(StatUpdateOption.class);
552+
// in posix -> posix, we can use the stat of the source, but if we're changing permissions and a BASIC vfs
553+
// is involved, we only want to try and change the "owner" permission, and leave everything else as-is
554+
VirtualFileStat updateStat = sourcePath.getStat();
555+
556+
if (changes.isPermissionModified(this.skipPermissions)) {
557+
options.add(StatUpdateOption.PERMISSIONS);
558+
}
559+
560+
if (changes.isTimestampsModified()) {
561+
options.add(StatUpdateOption.TIMESTAMPS);
562+
}
563+
564+
targetVfs.updateStat(targetPath, updateStat, options);
544565

545566
result.incrementStatsUpdated();
546567
}

jsync-engine/src/main/java/com/fizzed/jsync/engine/JsyncPathChanges.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,20 @@ public boolean isDeferredProcessing(boolean ignoreTimes) {
7979
&& checksum == null;
8080
}
8181

82-
public boolean isStatModified() {
82+
public boolean isPermissionModified(boolean skipPermissions) {
83+
return this.missing
84+
|| (!skipPermissions && this.permissions);
85+
}
86+
87+
public boolean isTimestampsModified() {
88+
return this.missing
89+
|| this.timestamps;
90+
}
91+
92+
public boolean isStatModified(boolean skipPermissions) {
8393
return this.missing
8494
|| this.timestamps
85-
|| this.permissions
95+
|| (!skipPermissions && this.permissions)
8696
|| this.ownership;
8797
}
8898

jsync-engine/src/test/java/com/fizzed/jsync/engine/JsyncDemo.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static public void main(String[] args) throws Exception {
3939
.setDelete(true)
4040
.setParents(true)
4141
.setForce(true)
42+
//.setSkipPermissions(true)
4243
//.setIgnoreTimes(true)
4344
//.setMaxFilesMaybeModifiedLimit(256)
4445
// .setProgress(true)

jsync-sftp/src/main/java/com/fizzed/jsync/sftp/SftpVirtualFileSystem.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -272,23 +272,23 @@ public VirtualPath stat(VirtualPath path) throws IOException {
272272
}
273273

274274
@Override
275-
public void updateStat(VirtualPath path, VirtualFileStat stat) throws IOException {
275+
public void updateStat(VirtualPath path, VirtualFileStat stat, Collection<StatUpdateOption> options) throws IOException {
276276
try {
277277
final SftpATTRS attrs = SftpATTRSAccessor.createSftpATTRS();
278278

279279
// TODO: are we updating uid/gid?
280280
Integer uid = null;
281281
Integer gid = null;
282282

283-
// TODO: are we updating permissions?
284-
// Integer perms = null;
285-
int perms = stat.getPermissions();
286-
attrs.setPERMISSIONS(perms);
283+
if (options.contains(StatUpdateOption.PERMISSIONS)) {
284+
attrs.setPERMISSIONS(stat.getPermissions());
285+
}
287286

288-
// are we updating mtime/atime?d
289-
int mtime = (int)(stat.getModifiedTime()/1000);
290-
int atime = (int)(stat.getAccessedTime()/1000);
291-
attrs.setACMODTIME(atime, mtime);
287+
if (options.contains(StatUpdateOption.TIMESTAMPS)) {
288+
int mtime = (int) (stat.getModifiedTime() / 1000);
289+
int atime = (int) (stat.getAccessedTime() / 1000);
290+
attrs.setACMODTIME(atime, mtime);
291+
}
292292

293293
this.sftp.setStat(path.toString(), attrs);
294294
} catch (SftpException e) {

jsync-vfs/src/main/java/com/fizzed/jsync/vfs/LocalVirtualFileSystem.java

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@
1010
import java.io.OutputStream;
1111
import java.nio.file.*;
1212
import java.nio.file.attribute.*;
13-
import java.util.ArrayList;
14-
import java.util.Iterator;
15-
import java.util.List;
16-
import java.util.Set;
13+
import java.util.*;
1714
import java.util.stream.Stream;
1815

1916
import static java.util.Arrays.asList;
@@ -130,7 +127,7 @@ protected VirtualPath withStat(VirtualPath path) throws IOException {
130127
perms = Permissions.toPosixInt(posixAttrs.permissions());
131128
} else {
132129
// use basic permissions, usually ends up being 700 from what I can gather
133-
final Set<PosixFilePermission> simulatedPosixPermissions = Permissions.getPosixPermissions(nativePath);
130+
final Set<PosixFilePermission> simulatedPosixPermissions = Permissions.toBasicPermissions(nativePath);
134131
perms = Permissions.toPosixInt(simulatedPosixPermissions);
135132
}
136133

@@ -147,20 +144,38 @@ public VirtualPath stat(VirtualPath path) throws IOException {
147144
}
148145

149146
@Override
150-
public void updateStat(VirtualPath path, VirtualFileStat stat) throws IOException {
147+
public void updateStat(VirtualPath path, VirtualFileStat stat, Collection<StatUpdateOption> options) throws IOException {
151148
final Path nativePath = this.toNativePath(path);
152149

153-
// Get the "View" (This is a lightweight handle to the attributes)
154-
BasicFileAttributeView view = Files.getFileAttributeView(nativePath, BasicFileAttributeView.class);
150+
final PosixFileAttributeView posixView;
151+
final BasicFileAttributeView view;
152+
if (this.posix) {
153+
posixView = Files.getFileAttributeView(nativePath, PosixFileAttributeView.class);
154+
view = posixView;
155+
} else {
156+
posixView = null;
157+
view = Files.getFileAttributeView(nativePath, BasicFileAttributeView.class);
158+
}
155159

156-
// 2. Prepare the times
157-
FileTime newModifiedTime = FileTime.fromMillis(stat.getModifiedTime());
158-
FileTime newAccessedTime = FileTime.fromMillis(stat.getAccessedTime());
160+
if (options.contains(StatUpdateOption.PERMISSIONS)) {
161+
final Set<PosixFilePermission> posixFilePermissions = Permissions.toPosixFilePermissions(stat.getPermissions());
162+
if (posixView != null) {
163+
posixView.setPermissions(posixFilePermissions);
164+
} else {
165+
Permissions.setBasicPermissions(nativePath, posixFilePermissions);
166+
}
167+
}
168+
169+
if (options.contains(StatUpdateOption.TIMESTAMPS)) {
170+
// 2. Prepare the times
171+
FileTime newModifiedTime = FileTime.fromMillis(stat.getModifiedTime());
172+
FileTime newAccessedTime = FileTime.fromMillis(stat.getAccessedTime());
159173

160-
// 3. Update all three in ONE operation
161-
// Signature: setTimes(lastModified, lastAccess, createTime)
162-
// Pass 'null' if you want to leave a specific timestamp unchanged.
163-
view.setTimes(newModifiedTime, newAccessedTime, null);
174+
// 3. Update all three in ONE operation
175+
// Signature: setTimes(lastModified, lastAccess, createTime)
176+
// Pass 'null' if you want to leave a specific timestamp unchanged.
177+
view.setTimes(newModifiedTime, newAccessedTime, null);
178+
}
164179
}
165180

166181
@Override
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.fizzed.jsync.vfs;
2+
3+
public enum StatUpdateOption {
4+
5+
OWNERSHIP,
6+
PERMISSIONS,
7+
TIMESTAMPS;
8+
9+
}

jsync-vfs/src/main/java/com/fizzed/jsync/vfs/VirtualFileSystem.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.io.InputStream;
55
import java.io.OutputStream;
66
import java.nio.file.NoSuchFileException;
7+
import java.util.Collection;
78
import java.util.List;
89
import java.util.Set;
910

@@ -61,7 +62,7 @@ default VirtualPath exists(VirtualPath path) throws IOException {
6162
*/
6263
VirtualPath stat(VirtualPath path) throws IOException;
6364

64-
void updateStat(VirtualPath path, VirtualFileStat stats) throws IOException;
65+
void updateStat(VirtualPath path, VirtualFileStat stats, Collection<StatUpdateOption> options) throws IOException;
6566

6667
List<VirtualPath> ls(VirtualPath path) throws IOException;
6768

jsync-vfs/src/main/java/com/fizzed/jsync/vfs/util/Permissions.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.fizzed.jsync.vfs.util;
22

3+
import java.io.File;
34
import java.io.IOException;
45
import java.nio.file.Files;
56
import java.nio.file.Path;
@@ -72,7 +73,7 @@ public static Set<PosixFilePermission> toPosixFilePermissions(int permissions) {
7273
return perms;
7374
}
7475

75-
static public Set<PosixFilePermission> getPosixPermissions(Path path) throws IOException {
76+
static public Set<PosixFilePermission> toBasicPermissions(Path path) throws IOException {
7677
// 2. On Windows: Synthesize permissions based on "DOS" attributes
7778
Set<PosixFilePermission> perms = new HashSet<>();
7879

@@ -99,4 +100,32 @@ static public Set<PosixFilePermission> getPosixPermissions(Path path) throws IOE
99100
return perms;
100101
}
101102

103+
static public void setBasicPermissions(Path path, Set<PosixFilePermission> perms) {
104+
File file = path.toFile();
105+
106+
// --- READ ---
107+
if (perms.contains(PosixFilePermission.OTHERS_READ)) {
108+
// If World needs read, open to Everyone (false = not owner only)
109+
file.setReadable(true, false);
110+
} else {
111+
// Otherwise, set specifically for Owner (true = owner only)
112+
// If OWNER_READ is missing, this sets readable to FALSE for owner
113+
file.setReadable(perms.contains(PosixFilePermission.OWNER_READ), true);
114+
}
115+
116+
// --- WRITE ---
117+
if (perms.contains(PosixFilePermission.OTHERS_WRITE)) {
118+
file.setWritable(true, false);
119+
} else {
120+
file.setWritable(perms.contains(PosixFilePermission.OWNER_WRITE), true);
121+
}
122+
123+
// --- EXECUTE ---
124+
if (perms.contains(PosixFilePermission.OTHERS_EXECUTE)) {
125+
file.setExecutable(true, false);
126+
} else {
127+
file.setExecutable(perms.contains(PosixFilePermission.OWNER_EXECUTE), true);
128+
}
129+
}
130+
102131
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.fizzed.jsync.vfs.util;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import static org.junit.jupiter.api.Assertions.*;
6+
7+
class PermissionsTest {
8+
9+
10+
11+
}

0 commit comments

Comments
 (0)