e7ecedaaed2b674fea066392f13f7c9c3b44aaff
[metze/samba/wip.git] / source3 / modules / vfs_streams_depot.c
1 /*
2  * Store streams in a separate subdirectory
3  *
4  * Copyright (C) Volker Lendecke, 2007
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21
22 #undef DBGC_CLASS
23 #define DBGC_CLASS DBGC_VFS
24
25 /*
26  * Excerpt from a mail from tridge:
27  *
28  * Volker, what I'm thinking of is this:
29  * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream1
30  * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream2
31  *
32  * where XX/YY is a 2 level hash based on the fsid/inode. "aaaa.bbbb"
33  * is the fsid/inode. "namedstreamX" is a file named after the stream
34  * name.
35  */
36
37 static uint32_t hash_fn(DATA_BLOB key)
38 {
39         uint32_t value; /* Used to compute the hash value.  */
40         uint32_t i;     /* Used to cycle through random values. */
41
42         /* Set the initial value from the key size. */
43         for (value = 0x238F13AF * key.length, i=0; i < key.length; i++)
44                 value = (value + (key.data[i] << (i*5 % 24)));
45
46         return (1103515243 * value + 12345);
47 }
48
49 /*
50  * With the hashing scheme based on the inode we need to protect against
51  * streams showing up on files with re-used inodes. This can happen if we
52  * create a stream directory from within Samba, and a local process or NFS
53  * client deletes the file without deleting the streams directory. When the
54  * inode is re-used and the stream directory is still around, the streams in
55  * there would be show up as belonging to the new file.
56  *
57  * There are several workarounds for this, probably the easiest one is on
58  * systems which have a true birthtime stat element: When the file has a later
59  * birthtime than the streams directory, then we have to recreate the
60  * directory.
61  *
62  * The other workaround is to somehow mark the file as generated by Samba with
63  * something that a NFS client would not do. The closest one is a special
64  * xattr value being set. On systems which do not support xattrs, it might be
65  * an option to put in a special ACL entry for a non-existing group.
66  */
67
68 #define SAMBA_XATTR_MARKER "user.SAMBA_STREAMS"
69
70 static bool file_is_valid(vfs_handle_struct *handle, const char *path)
71 {
72         char buf;
73
74         DEBUG(10, ("file_is_valid (%s) called\n", path));
75
76         if (SMB_VFS_NEXT_GETXATTR(handle, path, SAMBA_XATTR_MARKER,
77                                   &buf, sizeof(buf)) != sizeof(buf)) {
78                 DEBUG(10, ("GETXATTR failed: %s\n", strerror(errno)));
79                 return false;
80         }
81
82         if (buf != '1') {
83                 DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
84                 return false;
85         }
86
87         return true;
88 }
89
90 static bool mark_file_valid(vfs_handle_struct *handle, const char *path)
91 {
92         char buf = '1';
93         int ret;
94
95         DEBUG(10, ("marking file %s as valid\n", path));
96
97         ret = SMB_VFS_NEXT_SETXATTR(handle, path, SAMBA_XATTR_MARKER,
98                                     &buf, sizeof(buf), 0);
99
100         if (ret == -1) {
101                 DEBUG(10, ("SETXATTR failed: %s\n", strerror(errno)));
102                 return false;
103         }
104
105         return true;
106 }
107
108 static char *stream_dir(vfs_handle_struct *handle, const char *base_path,
109                         const SMB_STRUCT_STAT *base_sbuf, bool create_it)
110 {
111         uint32_t hash;
112         char *result = NULL;
113         SMB_STRUCT_STAT sbuf;
114         uint8_t first, second;
115         char *tmp;
116         char *id_hex;
117         struct file_id id;
118         uint8 id_buf[16];
119
120         tmp = talloc_asprintf(talloc_tos(), "%s/.streams", handle->conn->connectpath);
121
122         if (tmp == NULL) {
123                 errno = ENOMEM;
124                 goto fail;
125         }
126
127         const char *rootdir = lp_parm_const_string(
128                 SNUM(handle->conn), "streams_depot", "directory",
129                 tmp);
130         TALLOC_FREE(tmp);
131
132         if (base_sbuf == NULL) {
133                 if (SMB_VFS_NEXT_STAT(handle, base_path, &sbuf) == -1) {
134                         /*
135                          * base file is not there
136                          */
137                         goto fail;
138                 }
139                 base_sbuf = &sbuf;
140         }
141
142         id = SMB_VFS_FILE_ID_CREATE(handle->conn, base_sbuf->st_dev,
143                                     base_sbuf->st_ino);
144
145         push_file_id_16((char *)id_buf, &id);
146
147         hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
148
149         first = hash & 0xff;
150         second = (hash >> 8) & 0xff;
151
152         id_hex = hex_encode(talloc_tos(), id_buf, sizeof(id_buf));
153
154         if (id_hex == NULL) {
155                 errno = ENOMEM;
156                 goto fail;
157         }
158
159         result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
160                                  first, second, id_hex);
161
162         TALLOC_FREE(id_hex);
163
164         if (result == NULL) {
165                 errno = ENOMEM;
166                 return NULL;
167         }
168
169         if (SMB_VFS_NEXT_STAT(handle, result, &sbuf) == 0) {
170                 char *newname;
171
172                 if (!S_ISDIR(sbuf.st_mode)) {
173                         errno = EINVAL;
174                         goto fail;
175                 }
176
177                 if (file_is_valid(handle, base_path)) {
178                         return result;
179                 }
180
181                 /*
182                  * Someone has recreated a file under an existing inode
183                  * without deleting the streams directory. For now, just move
184                  * it away.
185                  */
186
187         again:
188                 newname = talloc_asprintf(talloc_tos(), "lost-%lu", random());
189                 if (newname == NULL) {
190                         errno = ENOMEM;
191                         goto fail;
192                 }
193
194                 if (SMB_VFS_NEXT_RENAME(handle, result, newname) == -1) {
195                         if ((errno == EEXIST) || (errno == ENOTEMPTY)) {
196                                 TALLOC_FREE(newname);
197                                 goto again;
198                         }
199                         goto fail;
200                 }
201
202                 TALLOC_FREE(newname);
203         }
204
205         if (!create_it) {
206                 errno = ENOENT;
207                 goto fail;
208         }
209
210         if ((SMB_VFS_NEXT_MKDIR(handle, rootdir, 0755) != 0)
211             && (errno != EEXIST)) {
212                 goto fail;
213         }
214
215         tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
216         if (tmp == NULL) {
217                 errno = ENOMEM;
218                 goto fail;
219         }
220
221         if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0)
222             && (errno != EEXIST)) {
223                 goto fail;
224         }
225
226         TALLOC_FREE(tmp);
227
228         tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
229                               second);
230         if (tmp == NULL) {
231                 errno = ENOMEM;
232                 goto fail;
233         }
234
235         if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0)
236             && (errno != EEXIST)) {
237                 goto fail;
238         }
239
240         TALLOC_FREE(tmp);
241
242         if ((SMB_VFS_NEXT_MKDIR(handle, result, 0755) != 0)
243             && (errno != EEXIST)) {
244                 goto fail;
245         }
246
247         if (!mark_file_valid(handle, base_path)) {
248                 goto fail;
249         }
250
251         return result;
252
253  fail:
254         TALLOC_FREE(result);
255         return NULL;
256 }
257
258 static char *stream_name(vfs_handle_struct *handle, const char *fname,
259                          bool create_dir)
260 {
261         char *base = NULL;
262         char *sname = NULL;
263         char *id_hex = NULL;
264         char *dirname, *stream_fname;
265
266         if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname,
267                                                     &base, &sname))) {
268                 DEBUG(10, ("split_ntfs_stream_name failed\n"));
269                 errno = ENOMEM;
270                 goto fail;
271         }
272
273         dirname = stream_dir(handle, base, NULL, create_dir);
274
275         if (dirname == NULL) {
276                 goto fail;
277         }
278
279         stream_fname = talloc_asprintf(talloc_tos(), "%s/:%s", dirname, sname);
280
281         if (stream_fname == NULL) {
282                 errno = ENOMEM;
283                 goto fail;
284         }
285
286         DEBUG(10, ("stream filename = %s\n", stream_fname));
287
288         TALLOC_FREE(base);
289         TALLOC_FREE(sname);
290         TALLOC_FREE(id_hex);
291
292         return stream_fname;
293
294  fail:
295         DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
296         TALLOC_FREE(base);
297         TALLOC_FREE(sname);
298         TALLOC_FREE(id_hex);
299         return NULL;
300 }
301
302 static NTSTATUS walk_streams(vfs_handle_struct *handle,
303                              const char *fname,
304                              const SMB_STRUCT_STAT *sbuf,
305                              char **pdirname,
306                              bool (*fn)(const char *dirname,
307                                         const char *dirent,
308                                         void *private_data),
309                              void *private_data)
310 {
311         char *dirname;
312         SMB_STRUCT_DIR *dirhandle = NULL;
313         char *dirent;
314
315         dirname = stream_dir(handle, fname, sbuf, false);
316
317         if (dirname == NULL) {
318                 if (errno == ENOENT) {
319                         /*
320                          * no stream around
321                          */
322                         return NT_STATUS_OK;
323                 }
324                 return map_nt_error_from_unix(errno);
325         }
326
327         DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
328
329         dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dirname, NULL, 0);
330
331         if (dirhandle == NULL) {
332                 TALLOC_FREE(dirname);
333                 return map_nt_error_from_unix(errno);
334         }
335
336         while ((dirent = vfs_readdirname(handle->conn, dirhandle)) != NULL) {
337
338                 if (ISDOT(dirent) || ISDOTDOT(dirent)) {
339                         continue;
340                 }
341
342                 DEBUG(10, ("walk_streams: dirent=%s\n", dirent));
343
344                 if (!fn(dirname, dirent, private_data)) {
345                         break;
346                 }
347         }
348
349         SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle);
350
351         if (pdirname != NULL) {
352                 *pdirname = dirname;
353         }
354         else {
355                 TALLOC_FREE(dirname);
356         }
357
358         return NT_STATUS_OK;
359 }
360
361 static int streams_depot_stat(vfs_handle_struct *handle, const char *fname,
362                               SMB_STRUCT_STAT *sbuf)
363 {
364         char *stream_fname;
365         int ret = -1;
366
367         DEBUG(10, ("streams_depot_stat called for [%s]\n", fname));
368
369         if (!is_ntfs_stream_name(fname)) {
370                 return SMB_VFS_NEXT_STAT(handle, fname, sbuf);
371         }
372
373         stream_fname = stream_name(handle, fname, false);
374         if (stream_fname == NULL) {
375                 goto done;
376         }
377
378         ret = SMB_VFS_NEXT_STAT(handle, stream_fname, sbuf);
379
380  done:
381         TALLOC_FREE(stream_fname);
382         return ret;
383 }
384
385 static int streams_depot_lstat(vfs_handle_struct *handle, const char *fname,
386                                SMB_STRUCT_STAT *sbuf)
387 {
388         char *stream_fname;
389         int ret = -1;
390
391         if (!is_ntfs_stream_name(fname)) {
392                 return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf);
393         }
394
395         stream_fname = stream_name(handle, fname, false);
396         if (stream_fname == NULL) {
397                 goto done;
398         }
399
400         ret = SMB_VFS_NEXT_LSTAT(handle, stream_fname, sbuf);
401
402  done:
403         TALLOC_FREE(stream_fname);
404         return ret;
405 }
406
407 static int streams_depot_open(vfs_handle_struct *handle,  const char *fname,
408                               files_struct *fsp, int flags, mode_t mode)
409 {
410         TALLOC_CTX *frame;
411         char *base = NULL;
412         SMB_STRUCT_STAT base_sbuf;
413         char *stream_fname;
414         int ret = -1;
415
416         if (!is_ntfs_stream_name(fname)) {
417                 return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
418         }
419
420         frame = talloc_stackframe();
421
422         if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname,
423                                                     &base, NULL))) {
424                 errno = ENOMEM;
425                 goto done;
426         }
427
428         ret = SMB_VFS_NEXT_STAT(handle, base, &base_sbuf);
429
430         if (ret == -1) {
431                 goto done;
432         }
433
434         TALLOC_FREE(base);
435
436         stream_fname = stream_name(handle, fname, true);
437         if (stream_fname == NULL) {
438                 goto done;
439         }
440
441         ret = SMB_VFS_NEXT_OPEN(handle, stream_fname, fsp, flags, mode);
442
443  done:
444         TALLOC_FREE(frame);
445         return ret;
446 }
447
448 static int streams_depot_unlink(vfs_handle_struct *handle,  const char *fname)
449 {
450         int ret = -1;
451         SMB_STRUCT_STAT sbuf;
452
453         DEBUG(10, ("streams_depot_unlink called for %s\n", fname));
454
455         if (is_ntfs_stream_name(fname)) {
456                 char *stream_fname;
457
458                 stream_fname = stream_name(handle, fname, false);
459                 if (stream_fname == NULL) {
460                         return -1;
461                 }
462
463                 ret = SMB_VFS_NEXT_UNLINK(handle, stream_fname);
464
465                 TALLOC_FREE(stream_fname);
466                 return ret;
467         }
468
469         /*
470          * We potentially need to delete the per-inode streams directory
471          */
472
473         if (SMB_VFS_NEXT_STAT(handle, fname, &sbuf) == -1) {
474                 return -1;
475         }
476
477         if (sbuf.st_nlink == 1) {
478                 char *dirname = stream_dir(handle, fname, &sbuf, false);
479
480                 if (dirname != NULL) {
481                         SMB_VFS_NEXT_RMDIR(handle, dirname);
482                 }
483                 TALLOC_FREE(dirname);
484         }
485
486         return SMB_VFS_NEXT_UNLINK(handle, fname);
487 }
488
489 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
490                            struct stream_struct **streams,
491                            const char *name, SMB_OFF_T size,
492                            SMB_OFF_T alloc_size)
493 {
494         struct stream_struct *tmp;
495
496         tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct,
497                                    (*num_streams)+1);
498         if (tmp == NULL) {
499                 return false;
500         }
501
502         tmp[*num_streams].name = talloc_strdup(tmp, name);
503         if (tmp[*num_streams].name == NULL) {
504                 return false;
505         }
506
507         tmp[*num_streams].size = size;
508         tmp[*num_streams].alloc_size = alloc_size;
509
510         *streams = tmp;
511         *num_streams += 1;
512         return true;
513 }
514
515 struct streaminfo_state {
516         TALLOC_CTX *mem_ctx;
517         vfs_handle_struct *handle;
518         unsigned int num_streams;
519         struct stream_struct *streams;
520         NTSTATUS status;
521 };
522
523 static bool collect_one_stream(const char *dirname,
524                                const char *dirent,
525                                void *private_data)
526 {
527         struct streaminfo_state *state =
528                 (struct streaminfo_state *)private_data;
529         char *full_sname;
530         SMB_STRUCT_STAT sbuf;
531
532         if (asprintf(&full_sname, "%s/%s", dirname, dirent) == -1) {
533                 state->status = NT_STATUS_NO_MEMORY;
534                 return false;
535         }
536         if (SMB_VFS_NEXT_STAT(state->handle, full_sname, &sbuf) == -1) {
537                 DEBUG(10, ("Could not stat %s: %s\n", full_sname,
538                            strerror(errno)));
539                 SAFE_FREE(full_sname);
540                 return true;
541         }
542
543         SAFE_FREE(full_sname);
544
545         if (!add_one_stream(state->mem_ctx,
546                             &state->num_streams, &state->streams,
547                             dirent, sbuf.st_size,
548                             get_allocation_size(
549                                     state->handle->conn, NULL, &sbuf))) {
550                 state->status = NT_STATUS_NO_MEMORY;
551                 return false;
552         }
553
554         return true;
555 }
556
557 static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
558                                          struct files_struct *fsp,
559                                          const char *fname,
560                                          TALLOC_CTX *mem_ctx,
561                                          unsigned int *pnum_streams,
562                                          struct stream_struct **pstreams)
563 {
564         SMB_STRUCT_STAT sbuf;
565         int ret;
566         NTSTATUS status;
567         struct streaminfo_state state;
568
569         if ((fsp != NULL) && (fsp->fh->fd != -1)) {
570                 if (is_ntfs_stream_name(fsp->fsp_name)) {
571                         return NT_STATUS_INVALID_PARAMETER;
572                 }
573                 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf);
574         }
575         else {
576                 if (is_ntfs_stream_name(fname)) {
577                         return NT_STATUS_INVALID_PARAMETER;
578                 }
579                 ret = SMB_VFS_NEXT_STAT(handle, fname, &sbuf);
580         }
581
582         if (ret == -1) {
583                 return map_nt_error_from_unix(errno);
584         }
585
586         state.streams = NULL;
587         state.num_streams = 0;
588
589         if (!S_ISDIR(sbuf.st_mode)) {
590                 if (!add_one_stream(mem_ctx,
591                                     &state.num_streams, &state.streams,
592                                     "::$DATA", sbuf.st_size,
593                                     get_allocation_size(handle->conn, fsp,
594                                                         &sbuf))) {
595                         return NT_STATUS_NO_MEMORY;
596                 }
597         }
598
599         state.mem_ctx = mem_ctx;
600         state.handle = handle;
601         state.status = NT_STATUS_OK;
602
603         status = walk_streams(handle, fname, &sbuf, NULL, collect_one_stream,
604                               &state);
605
606         if (!NT_STATUS_IS_OK(status)) {
607                 TALLOC_FREE(state.streams);
608                 return status;
609         }
610
611         if (!NT_STATUS_IS_OK(state.status)) {
612                 TALLOC_FREE(state.streams);
613                 return state.status;
614         }
615
616         *pnum_streams = state.num_streams;
617         *pstreams = state.streams;
618         return NT_STATUS_OK;
619 }
620
621 static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle)
622 {
623         return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
624 }
625
626 /* VFS operations structure */
627
628 static vfs_op_tuple streams_depot_ops[] = {
629         {SMB_VFS_OP(streams_depot_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
630          SMB_VFS_LAYER_TRANSPARENT},
631         {SMB_VFS_OP(streams_depot_open), SMB_VFS_OP_OPEN,
632          SMB_VFS_LAYER_TRANSPARENT},
633         {SMB_VFS_OP(streams_depot_stat), SMB_VFS_OP_STAT,
634          SMB_VFS_LAYER_TRANSPARENT},
635         {SMB_VFS_OP(streams_depot_lstat), SMB_VFS_OP_LSTAT,
636          SMB_VFS_LAYER_TRANSPARENT},
637         {SMB_VFS_OP(streams_depot_unlink), SMB_VFS_OP_UNLINK,
638          SMB_VFS_LAYER_TRANSPARENT},
639         {SMB_VFS_OP(streams_depot_streaminfo), SMB_VFS_OP_STREAMINFO,
640          SMB_VFS_LAYER_OPAQUE},
641         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
642 };
643
644 NTSTATUS vfs_streams_depot_init(void);
645 NTSTATUS vfs_streams_depot_init(void)
646 {
647         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
648                                 streams_depot_ops);
649 }