ref: df0f9b75a74c4fc2241bc1a85e605aa080d71bfd
parent: f784be8431711c15cbc1f0a60168303a6764405d
author: kvik <kvik@a-b.xyz>
date: Tue May 14 13:50:51 EDT 2019
implement shadow tree for file creation previously, creation of new files was first attempted in the branch marked for creation (-c flag) and if that couldn't happen (because of the path leading to the file not existing in the branch) the union list was searched in-order until the path was found, and the file was created there. this was good enough for the most basic usages, like the unioning of /bin, in which case if could be considered useful to route new files into matching branches; but this behaviour can have unpredictable results and requires somewhat careful thought to use advantageously. forcing the creation of new files in the shadow tree, i.e. the one marked with a -c flag, is an intuitive, easy to understand concept that is also a very useful default for the kind of usage this file server was intended for. going back to our most basic example of /bin, the user of unionfs will probably want all the new files and directories created under /bin to end up in his $home/bin/rc directory, instead of getting sprinkled out over the system paths. another very useful usage scenario enabled by this is build overlays, where the build artifacts can be transparently collected into a ramfs for improved speed and ease of cleanup. this change neccesitates thinking about and eventually adding a copy-on-write scheme for file modifications, which would facilitate experimenting with read-only 9front live images with persistable overlays, or something... :)
--- a/unionfs.c
+++ b/unionfs.c
@@ -468,6 +468,39 @@
respond(r, nil);
}
+int
+mkdirp(char *path)
+{
+ int fd;
+ char *p;
+ Dir *d;
+
+ assert(path != nil);
+ if((d = dirstat(path)) != nil){
+ free(d);
+ return 1;
+ }
+ path = p = strdup(path);
+ for(; p != nil ;){
+ if(p[0] == '/')
+ p++;
+ if(p = strchr(p, '/'))
+ *p = 0;
+ if((d = dirstat(path)) == nil){
+ if((fd = create(path, 0, 0777|DMDIR)) < 0){
+ free(path);
+ return -1;
+ }
+ close(fd);
+ }
+ free(d);
+ if(p != nil)
+ *p++ = '/';
+ }
+ free(path);
+ return 1;
+}
+
void
fscreate(Req *r)
{
@@ -486,27 +519,11 @@
for(u = unionlist->next; u != unionlist; u = u->next)
if(u->create == 1)
break;
- assert(u != unionlist);
path = mkpath(u->root, f->fspath, nil);
- d = dirstat(path);
- if(d != nil){
- free(d);
- goto work;
+ if(mkdirp(path) < 0){
+ responderror(r);
+ return;
}
- for(u = unionlist->next; u != unionlist; u = u->next){
- if(u->create == 1)
- continue;
- free(path);
- path = mkpath(u->root, f->fspath, nil);
- d = dirstat(path);
- if(d != nil){
- free(d);
- goto work;
- }
- }
- sysfatal("something's fucked");
-
-work:
npath = mkpath(path, i->name, nil);
free(path);
st = emalloc(sizeof(*st));