"Pull only" folder type


I was wondering if somebody is already working on a “pull only” folder type.

Based on your answers for my previous post, we’re looking into setting up a tree-like structure due to the sheer number of nodes we’ll have if we move forward with Syncthing.

We have the need to ensure that changes are only “pushed down” from the master servers and no changes on a child node would make it back up through the tree.

If nobody is working on it already, would anybody have some pointers to help us get started to make these modifications and send a pull-request back in?

Or even better, is there a way to accomplish this without modifying Syncthing?

Thanks! Heiko

I am not aware of anyone working on this. If you have questions about.

You can accomplish this by making your filesystem potentially read only, or syncing to a folder with rw access and then exposing it to users via readonly bind mount.

Alternatively using permissions preventing other apps from writing.

If you have qiestions about the pull request - ask.

It would be helpful if anybody would have pointers on which files we’d actually have to modify to implement a feature like this. Any other directions would be helpful too.

I’m still trying to figure out if we have somebody with the right knowledge and time.

Thx Heiko

https://github.com/syncthing/syncthing/blob/master/lib/model/rofolder.go master folder https://github.com/syncthing/syncthing/blob/master/lib/model/rwfolder.go normal folder

I expect you’d implement wofolder which would be something like rwfolder yet instead of sending out updates as it detects changes it would roll back the local version of the file (or remove it all together) and schedule a pull.

Thanks for the information, that is very helpful.

I took a quick look at rwfolder.go and it seem we’d have a lot of duplication in wofolder.go . We’d probably have to look at making this a bit cleaner.

I guess it’s time to start learning go. :wink:


I’ve been going over the code, trying to understand how this all works.

Am I understanding this correctly that the scanner will update the local database with any local file changes? I haven’t figured out yet how I can tie into this to undo the changes and also prevent that any local changes get announced to other nodes.

Any more pointers would be greatly appreciated.

Thx Heiko

I think you should announce the file as invalid (declaring you don’t have it anymore) and potentially tweak them somehow so that they locally match the WithNeed database iterator condition.

Carbon Copy Cloner has this feature. I call it “Contribute”. It’s done with two settings in customise.

Looking for some feedback on the 2 options I found so far.

Option 1 The most reliable way I have found so far, is the following: Enhance walk.go and set the invalid flag on each file that changed. Enhance rwfolder.go and trigger f.model.RestartFolder after local changes have been detected and logged. Obviously this would need a folder-level configuration parameter, like “RejectLocalChanges”, to trigger this behavior.

Option 2 I haven’t had much luck with the WithNeed. I can get it to work sometimes, but I must still misunderstand how some of the functionality works. I added a function to basically reset the version number, so that it’s lower than the global version. This in turn will trigger the download, but only sometimes. I have to dig further on why it behaves this way. This would also mean minimal changes to rwfolder.go and walk.go, in addition to needing a configuration parameter on the folder to trigger this behavior.

This should not touch rwfolder.go, if anything it should implement a new folder type. RestartFodler should definately not be used as it means something different, you should check how rwfolder schedules the pull cycle and do that.

Maybe I missed the point, but isn’t this just a normal folder with rescan interval zero?

It’ll still detect conflicts that way, but not propagate the changes outwards.

It might need a way to disable the initial scan though if we really want to not propagate changes. Maybe rescan interval <0 could do that, or just a disableInitialScan flag.

Doesn’t it need the scan to detect which items are out of sync (have been modified locally) and need to be pulled again to undo the change?

They are looking for a folder that automatically removes the conflicting files and fetches the old version.

I like the idea as an accompaniment to a master folder… The local user sets the folder as a slave and expects automatic data loss.

If it could be coupled with the current versioning implementation it would be very handy.

1 Like

The changes seem pretty straight forward and might end up being only a couple lines of code.

If a local change gets detected in walk.go, then all I have to do is reset the version of the file so it’ll be part of WithNeed. The next step is to trigger a pull. Combine this with not keeping any sync conflicts and it seems to work quite nicely. I haven’t played with the versions yet. One step at a time…

I’m currently trying to figure out how I can trigger the pull after a local change is detected. I’m learning go at the same time, so it’s slow going (pun intended).

Just as some background: The feature I’m looking for is a need in order to implement syncthing in our corporate environment. This, in combination with proper directory permissions, will help ensure that no data can be pushed “up-stream”.

This part shows how to schedule a pull https://github.com/syncthing/syncthing/blob/master/lib/model/rwfolder.go#L196

(essentially resetting the time)

I know @calmh is against this feature, as it potentially nukes files from underneath peoples feet, but I feel this has been asked for too many times. I know you can achieve what you are asking for with file/folder permissions (by preveting people from writing), but you can’t guarantee applications don’t create temp files, people are not muppetsetc etc. Plus this is somewhat what https://github.com/syncthing/syncthing/issues/62 was supposed to do in the first place.

Yes that’s exactly what I’m intending to do. I need to trigger this from LocalChangeDetected (or one of the calling functions) in model.go. I’m currently trying to figure out how to do that.

What I’m trying to implement won’t help with any “untrusted” machines, since it prevents the sending of the files, not the receiving.

You’ll also need to create fake delete entries for new files. I remain extremely skeptical of this feature.

What are your concerns in regards to this feature? Maybe I can incorporate something to help resolve some of them.

My concern is essentially that it becomes plausible that someone will write and save a document to their sync folder, and everything will look fine and dandy, and sixty seconds later syncthing just outright deletes the file. Boom, gone, even though it was saved successfully.

Sure, it’s the users own fault for configuring it as a “pull only” folder and forgetting about it – but in the goal definition for Syncthing (which I have yet to write up properly I think) the number one thing at the very top of the list is that Syncthing should be safe. “Protecting the user’s data is paramount” is the phrase I’ve used and I believe quite strongly in that.

To that end Syncthing never modifies originals, tries hard to identify conflicts and saves both variants of the file, lets you set up versioning to keep around versions of files that it replaced, etc.

Having a mode where Syncthing just blows away any data you save or change is the exact opposite of treating the user’s data as precious and taking good care of it.

Maybe, possibly, some of this could be acceptable if it was mandatory to use it together with some kind of versioning…