root/source3/modules/vfs_streams_xattr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. stream_inode
  2. get_xattr_size
  3. streams_xattr_recheck
  4. streams_xattr_fstat
  5. streams_xattr_stat
  6. streams_xattr_lstat
  7. streams_xattr_open
  8. streams_xattr_unlink
  9. streams_xattr_rename
  10. walk_xattr_streams
  11. add_one_stream
  12. collect_one_stream
  13. streams_xattr_streaminfo
  14. streams_xattr_fs_capabilities
  15. streams_xattr_pwrite
  16. streams_xattr_pread
  17. streams_xattr_ftruncate
  18. vfs_streams_xattr_init

   1 /*
   2  * Store streams in xattrs
   3  *
   4  * Copyright (C) Volker Lendecke, 2008
   5  *
   6  * Partly based on James Peach's Darwin module, which is
   7  *
   8  * Copyright (C) James Peach 2006-2007
   9  *
  10  * This program is free software; you can redistribute it and/or modify
  11  * it under the terms of the GNU General Public License as published by
  12  * the Free Software Foundation; either version 3 of the License, or
  13  * (at your option) any later version.
  14  *
  15  * This program is distributed in the hope that it will be useful,
  16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18  * GNU General Public License for more details.
  19  *
  20  * You should have received a copy of the GNU General Public License
  21  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  22  */
  23 
  24 #include "includes.h"
  25 
  26 #undef DBGC_CLASS
  27 #define DBGC_CLASS DBGC_VFS
  28 
  29 struct stream_io {
  30         char *base;
  31         char *xattr_name;
  32         void *fsp_name_ptr;
  33         files_struct *fsp;
  34         vfs_handle_struct *handle;
  35 };
  36 
  37 static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
     /* [<][>][^][v][top][bottom][index][help] */
  38 {
  39         struct MD5Context ctx;
  40         unsigned char hash[16];
  41         SMB_INO_T result;
  42         char *upper_sname;
  43 
  44         DEBUG(10, ("stream_inode called for %lu/%lu [%s]\n",
  45                    (unsigned long)sbuf->st_dev,
  46                    (unsigned long)sbuf->st_ino, sname));
  47 
  48         upper_sname = talloc_strdup_upper(talloc_tos(), sname);
  49         SMB_ASSERT(upper_sname != NULL);
  50 
  51         MD5Init(&ctx);
  52         MD5Update(&ctx, (unsigned char *)&(sbuf->st_dev),
  53                   sizeof(sbuf->st_dev));
  54         MD5Update(&ctx, (unsigned char *)&(sbuf->st_ino),
  55                   sizeof(sbuf->st_ino));
  56         MD5Update(&ctx, (unsigned char *)upper_sname,
  57                   talloc_get_size(upper_sname)-1);
  58         MD5Final(hash, &ctx);
  59 
  60         TALLOC_FREE(upper_sname);
  61 
  62         /* Hopefully all the variation is in the lower 4 (or 8) bytes! */
  63         memcpy(&result, hash, sizeof(result));
  64 
  65         DEBUG(10, ("stream_inode returns %lu\n", (unsigned long)result));
  66 
  67         return result;
  68 }
  69 
  70 static ssize_t get_xattr_size(connection_struct *conn,
     /* [<][>][^][v][top][bottom][index][help] */
  71                                 files_struct *fsp,
  72                                 const char *fname,
  73                                 const char *xattr_name)
  74 {
  75         NTSTATUS status;
  76         struct ea_struct ea;
  77         ssize_t result;
  78 
  79         status = get_ea_value(talloc_tos(), conn, fsp, fname,
  80                               xattr_name, &ea);
  81 
  82         if (!NT_STATUS_IS_OK(status)) {
  83                 return -1;
  84         }
  85 
  86         result = ea.value.length-1;
  87         TALLOC_FREE(ea.value.data);
  88         return result;
  89 }
  90 
  91 static bool streams_xattr_recheck(struct stream_io *sio)
     /* [<][>][^][v][top][bottom][index][help] */
  92 {
  93         NTSTATUS status;
  94         char *base = NULL;
  95         char *sname = NULL;
  96         char *xattr_name = NULL;
  97 
  98         if (sio->fsp->fsp_name == sio->fsp_name_ptr) {
  99                 return true;
 100         }
 101 
 102         status = split_ntfs_stream_name(talloc_tos(), sio->fsp->fsp_name,
 103                                         &base, &sname);
 104         if (!NT_STATUS_IS_OK(status)) {
 105                 return false;
 106         }
 107 
 108         if (sname == NULL) {
 109                 /* how can this happen */
 110                 errno = EINVAL;
 111                 return false;
 112         }
 113 
 114         xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
 115                                      SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
 116         if (xattr_name == NULL) {
 117                 return false;
 118         }
 119 
 120         TALLOC_FREE(sio->xattr_name);
 121         TALLOC_FREE(sio->base);
 122         sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
 123                                         xattr_name);
 124         sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
 125                                   base);
 126         sio->fsp_name_ptr = sio->fsp->fsp_name;
 127 
 128         if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
 129                 return false;
 130         }
 131 
 132         return true;
 133 }
 134 
 135 static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
     /* [<][>][^][v][top][bottom][index][help] */
 136                                SMB_STRUCT_STAT *sbuf)
 137 {
 138         int ret = -1;
 139         struct stream_io *io = (struct stream_io *)
 140                 VFS_FETCH_FSP_EXTENSION(handle, fsp);
 141 
 142         DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp->fh->fd));
 143 
 144         if (io == NULL || fsp->base_fsp == NULL) {
 145                 return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
 146         }
 147 
 148         if (!streams_xattr_recheck(io)) {
 149                 return -1;
 150         }
 151 
 152         if (lp_posix_pathnames()) {
 153                 ret = SMB_VFS_LSTAT(handle->conn, io->base, sbuf);
 154         } else {
 155                 ret = SMB_VFS_STAT(handle->conn, io->base, sbuf);
 156         }
 157 
 158         if (ret == -1) {
 159                 return -1;
 160         }
 161 
 162         sbuf->st_size = get_xattr_size(handle->conn, fsp->base_fsp,
 163                                         io->base, io->xattr_name);
 164         if (sbuf->st_size == -1) {
 165                 return -1;
 166         }
 167 
 168         DEBUG(10, ("sbuf->st_size = %d\n", (int)sbuf->st_size));
 169 
 170         sbuf->st_ino = stream_inode(sbuf, io->xattr_name);
 171         sbuf->st_mode &= ~S_IFMT;
 172         sbuf->st_mode |= S_IFREG;
 173         sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
 174 
 175         return 0;
 176 }
 177 
 178 static int streams_xattr_stat(vfs_handle_struct *handle, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 179                               SMB_STRUCT_STAT *sbuf)
 180 {
 181         NTSTATUS status;
 182         char *base = NULL, *sname = NULL;
 183         int result = -1;
 184         char *xattr_name;
 185 
 186         if (!is_ntfs_stream_name(fname)) {
 187                 return SMB_VFS_NEXT_STAT(handle, fname, sbuf);
 188         }
 189 
 190         status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
 191         if (!NT_STATUS_IS_OK(status)) {
 192                 errno = EINVAL;
 193                 return -1;
 194         }
 195 
 196         if (sname == NULL){
 197                 return SMB_VFS_NEXT_STAT(handle, base, sbuf);
 198         }
 199 
 200         if (SMB_VFS_STAT(handle->conn, base, sbuf) == -1) {
 201                 goto fail;
 202         }
 203 
 204         xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
 205                                      SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
 206         if (xattr_name == NULL) {
 207                 errno = ENOMEM;
 208                 goto fail;
 209         }
 210 
 211         sbuf->st_size = get_xattr_size(handle->conn, NULL, base, xattr_name);
 212         if (sbuf->st_size == -1) {
 213                 errno = ENOENT;
 214                 goto fail;
 215         }
 216 
 217         sbuf->st_ino = stream_inode(sbuf, xattr_name);
 218         sbuf->st_mode &= ~S_IFMT;
 219         sbuf->st_mode |= S_IFREG;
 220         sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
 221 
 222         result = 0;
 223  fail:
 224         TALLOC_FREE(base);
 225         TALLOC_FREE(sname);
 226         return result;
 227 }
 228 
 229 static int streams_xattr_lstat(vfs_handle_struct *handle, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 230                                SMB_STRUCT_STAT *sbuf)
 231 {
 232         NTSTATUS status;
 233         char *base, *sname;
 234         int result = -1;
 235         char *xattr_name;
 236 
 237         if (!is_ntfs_stream_name(fname)) {
 238                 return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf);
 239         }
 240 
 241         status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
 242         if (!NT_STATUS_IS_OK(status)) {
 243                 errno = EINVAL;
 244                 goto fail;
 245         }
 246 
 247         if (sname == NULL){
 248                 return SMB_VFS_NEXT_LSTAT(handle, base, sbuf);
 249         }
 250 
 251         if (SMB_VFS_LSTAT(handle->conn, base, sbuf) == -1) {
 252                 goto fail;
 253         }
 254 
 255         xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
 256                                      SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
 257         if (xattr_name == NULL) {
 258                 errno = ENOMEM;
 259                 goto fail;
 260         }
 261 
 262         sbuf->st_size = get_xattr_size(handle->conn, NULL, base, xattr_name);
 263         if (sbuf->st_size == -1) {
 264                 errno = ENOENT;
 265                 goto fail;
 266         }
 267 
 268         sbuf->st_ino = stream_inode(sbuf, xattr_name);
 269         sbuf->st_mode &= ~S_IFMT;
 270         sbuf->st_mode |= S_IFREG;
 271         sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
 272 
 273         result = 0;
 274  fail:
 275         TALLOC_FREE(base);
 276         TALLOC_FREE(sname);
 277         return result;
 278 }
 279 
 280 static int streams_xattr_open(vfs_handle_struct *handle,  const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 281                               files_struct *fsp, int flags, mode_t mode)
 282 {
 283         TALLOC_CTX *frame;
 284         NTSTATUS status;
 285         struct stream_io *sio;
 286         char *base, *sname;
 287         struct ea_struct ea;
 288         char *xattr_name;
 289         int baseflags;
 290         int hostfd = -1;
 291 
 292         DEBUG(10, ("streams_xattr_open called for %s\n", fname));
 293 
 294         if (!is_ntfs_stream_name(fname)) {
 295                 return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
 296         }
 297 
 298         frame = talloc_stackframe();
 299 
 300         status = split_ntfs_stream_name(talloc_tos(), fname,
 301                                         &base, &sname);
 302         if (!NT_STATUS_IS_OK(status)) {
 303                 errno = EINVAL;
 304                 goto fail;
 305         }
 306 
 307         if (sname == NULL) {
 308                 hostfd = SMB_VFS_NEXT_OPEN(handle, base, fsp, flags, mode);
 309                 talloc_free(frame);
 310                 return hostfd;
 311         }
 312 
 313         xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
 314                                      SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
 315         if (xattr_name == NULL) {
 316                 errno = ENOMEM;
 317                 goto fail;
 318         }
 319 
 320         /*
 321          * We use baseflags to turn off nasty side-effects when opening the
 322          * underlying file.
 323          */
 324         baseflags = flags;
 325         baseflags &= ~O_TRUNC;
 326         baseflags &= ~O_EXCL;
 327         baseflags &= ~O_CREAT;
 328 
 329         hostfd = SMB_VFS_OPEN(handle->conn, base, fsp, baseflags, mode);
 330 
 331         /* It is legit to open a stream on a directory, but the base
 332          * fd has to be read-only.
 333          */
 334         if ((hostfd == -1) && (errno == EISDIR)) {
 335                 baseflags &= ~O_ACCMODE;
 336                 baseflags |= O_RDONLY;
 337                 hostfd = SMB_VFS_OPEN(handle->conn, fname, fsp, baseflags,
 338                                       mode);
 339         }
 340 
 341         if (hostfd == -1) {
 342                 goto fail;
 343         }
 344 
 345         status = get_ea_value(talloc_tos(), handle->conn, NULL, base,
 346                               xattr_name, &ea);
 347 
 348         DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status)));
 349 
 350         if (!NT_STATUS_IS_OK(status)
 351             && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
 352                 /*
 353                  * The base file is not there. This is an error even if we got
 354                  * O_CREAT, the higher levels should have created the base
 355                  * file for us.
 356                  */
 357                 DEBUG(10, ("streams_xattr_open: base file %s not around, "
 358                            "returning ENOENT\n", base));
 359                 errno = ENOENT;
 360                 goto fail;
 361         }
 362 
 363         if (!NT_STATUS_IS_OK(status)) {
 364                 /*
 365                  * The attribute does not exist
 366                  */
 367 
 368                 if (flags & O_CREAT) {
 369                         /*
 370                          * Darn, xattrs need at least 1 byte
 371                          */
 372                         char null = '\0';
 373 
 374                         DEBUG(10, ("creating attribute %s on file %s\n",
 375                                    xattr_name, base));
 376 
 377                         if (fsp->base_fsp->fh->fd != -1) {
 378                                 if (SMB_VFS_FSETXATTR(
 379                                         fsp->base_fsp, xattr_name,
 380                                         &null, sizeof(null),
 381                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
 382                                         goto fail;
 383                                 }
 384                         } else {
 385                                 if (SMB_VFS_SETXATTR(
 386                                         handle->conn, base, xattr_name,
 387                                         &null, sizeof(null),
 388                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
 389                                         goto fail;
 390                                 }
 391                         }
 392                 }
 393         }
 394 
 395         if (flags & O_TRUNC) {
 396                 char null = '\0';
 397                 if (fsp->base_fsp->fh->fd != -1) {
 398                         if (SMB_VFS_FSETXATTR(
 399                                         fsp->base_fsp, xattr_name,
 400                                         &null, sizeof(null),
 401                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
 402                                 goto fail;
 403                         }
 404                 } else {
 405                         if (SMB_VFS_SETXATTR(
 406                                         handle->conn, base, xattr_name,
 407                                         &null, sizeof(null),
 408                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
 409                                 goto fail;
 410                         }
 411                 }
 412         }
 413 
 414         sio = (struct stream_io *)VFS_ADD_FSP_EXTENSION(handle, fsp,
 415                                                         struct stream_io,
 416                                                         NULL);
 417         if (sio == NULL) {
 418                 errno = ENOMEM;
 419                 goto fail;
 420         }
 421 
 422         sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
 423                                         xattr_name);
 424         sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
 425                                   base);
 426         sio->fsp_name_ptr = fsp->fsp_name;
 427         sio->handle = handle;
 428         sio->fsp = fsp;
 429 
 430         if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
 431                 errno = ENOMEM;
 432                 goto fail;
 433         }
 434 
 435         TALLOC_FREE(frame);
 436         return hostfd;
 437 
 438  fail:
 439         if (hostfd >= 0) {
 440                 /*
 441                  * BUGBUGBUG -- we would need to call fd_close_posix here, but
 442                  * we don't have a full fsp yet
 443                  */
 444                 SMB_VFS_CLOSE(fsp);
 445         }
 446 
 447         TALLOC_FREE(frame);
 448         return -1;
 449 }
 450 
 451 static int streams_xattr_unlink(vfs_handle_struct *handle,  const char *fname)
     /* [<][>][^][v][top][bottom][index][help] */
 452 {
 453         NTSTATUS status;
 454         char *base = NULL;
 455         char *sname = NULL;
 456         int ret = -1;
 457         char *xattr_name;
 458 
 459         if (!is_ntfs_stream_name(fname)) {
 460                 return SMB_VFS_NEXT_UNLINK(handle, fname);
 461         }
 462 
 463         status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
 464         if (!NT_STATUS_IS_OK(status)) {
 465                 errno = EINVAL;
 466                 goto fail;
 467         }
 468 
 469         if (sname == NULL){
 470                 return SMB_VFS_NEXT_UNLINK(handle, base);
 471         }
 472 
 473         xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
 474                                      SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
 475         if (xattr_name == NULL) {
 476                 errno = ENOMEM;
 477                 goto fail;
 478         }
 479 
 480         ret = SMB_VFS_REMOVEXATTR(handle->conn, base, xattr_name);
 481 
 482         if ((ret == -1) && (errno == ENOATTR)) {
 483                 errno = ENOENT;
 484                 goto fail;
 485         }
 486 
 487         ret = 0;
 488 
 489  fail:
 490         TALLOC_FREE(base);
 491         TALLOC_FREE(sname);
 492         return ret;
 493 }
 494 
 495 static int streams_xattr_rename(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 496                                 const char *oldname,
 497                                 const char *newname)
 498 {
 499         NTSTATUS status;
 500         TALLOC_CTX *frame = NULL;
 501         char *obase;
 502         char *ostream;
 503         char *nbase;
 504         char *nstream;
 505         const char *base;
 506         int ret = -1;
 507         char *oxattr_name;
 508         char *nxattr_name;
 509         bool o_is_stream;
 510         bool n_is_stream;
 511         ssize_t oret;
 512         ssize_t nret;
 513         struct ea_struct ea;
 514 
 515         o_is_stream = is_ntfs_stream_name(oldname);
 516         n_is_stream = is_ntfs_stream_name(newname);
 517 
 518         if (!o_is_stream && !n_is_stream) {
 519                 return SMB_VFS_NEXT_RENAME(handle, oldname, newname);
 520         }
 521 
 522         frame = talloc_stackframe();
 523         if (!frame) {
 524                 goto fail;
 525         }
 526 
 527         status = split_ntfs_stream_name(talloc_tos(), oldname, &obase, &ostream);
 528         if (!NT_STATUS_IS_OK(status)) {
 529                 errno = EINVAL;
 530                 goto fail;
 531         }
 532 
 533         status = split_ntfs_stream_name(talloc_tos(), newname, &nbase, &nstream);
 534         if (!NT_STATUS_IS_OK(status)) {
 535                 errno = EINVAL;
 536                 goto fail;
 537         }
 538 
 539         /*TODO: maybe call SMB_VFS_NEXT_RENAME() both streams are NULL (::$DATA) */
 540         if (ostream == NULL) {
 541                 errno = ENOSYS;
 542                 goto fail;
 543         }
 544 
 545         if (nstream == NULL) {
 546                 errno = ENOSYS;
 547                 goto fail;
 548         }
 549 
 550         if (StrCaseCmp(ostream, nstream) == 0) {
 551                 goto done;
 552         }
 553 
 554         base = obase;
 555 
 556         oxattr_name = talloc_asprintf(talloc_tos(), "%s%s",
 557                                       SAMBA_XATTR_DOSSTREAM_PREFIX, ostream);
 558         if (oxattr_name == NULL) {
 559                 errno = ENOMEM;
 560                 goto fail;
 561         }
 562 
 563         nxattr_name = talloc_asprintf(talloc_tos(), "%s%s",
 564                                       SAMBA_XATTR_DOSSTREAM_PREFIX, nstream);
 565         if (nxattr_name == NULL) {
 566                 errno = ENOMEM;
 567                 goto fail;
 568         }
 569 
 570         /* read the old stream */
 571         status = get_ea_value(talloc_tos(), handle->conn, NULL,
 572                               base, oxattr_name, &ea);
 573         if (!NT_STATUS_IS_OK(status)) {
 574                 errno = ENOENT;
 575                 goto fail;
 576         }
 577 
 578         /* (over)write the new stream */
 579         nret = SMB_VFS_SETXATTR(handle->conn, base, nxattr_name,
 580                                 ea.value.data, ea.value.length, 0);
 581         if (nret < 0) {
 582                 if (errno == ENOATTR) {
 583                         errno = ENOENT;
 584                 }
 585                 goto fail;
 586         }
 587 
 588         /* remove the old stream */
 589         oret = SMB_VFS_REMOVEXATTR(handle->conn, base, oxattr_name);
 590         if (oret < 0) {
 591                 if (errno == ENOATTR) {
 592                         errno = ENOENT;
 593                 }
 594                 goto fail;
 595         }
 596 
 597  done:
 598         errno = 0;
 599         ret = 0;
 600  fail:
 601         TALLOC_FREE(frame);
 602         return ret;
 603 }
 604 
 605 static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
     /* [<][>][^][v][top][bottom][index][help] */
 606                                    const char *fname,
 607                                    bool (*fn)(struct ea_struct *ea,
 608                                               void *private_data),
 609                                    void *private_data)
 610 {
 611         NTSTATUS status;
 612         char **names;
 613         size_t i, num_names;
 614         size_t prefix_len = strlen(SAMBA_XATTR_DOSSTREAM_PREFIX);
 615 
 616         status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
 617                                         &names, &num_names);
 618         if (!NT_STATUS_IS_OK(status)) {
 619                 return status;
 620         }
 621 
 622         for (i=0; i<num_names; i++) {
 623                 struct ea_struct ea;
 624 
 625                 if (strncmp(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX,
 626                             prefix_len) != 0) {
 627                         continue;
 628                 }
 629 
 630                 status = get_ea_value(names, conn, fsp, fname, names[i], &ea);
 631                 if (!NT_STATUS_IS_OK(status)) {
 632                         DEBUG(10, ("Could not get ea %s for file %s: %s\n",
 633                                    names[i], fname, nt_errstr(status)));
 634                         continue;
 635                 }
 636 
 637                 ea.name = talloc_asprintf(ea.value.data, ":%s",
 638                                           names[i] + prefix_len);
 639                 if (ea.name == NULL) {
 640                         DEBUG(0, ("talloc failed\n"));
 641                         continue;
 642                 }
 643 
 644                 if (!fn(&ea, private_data)) {
 645                         TALLOC_FREE(ea.value.data);
 646                         return NT_STATUS_OK;
 647                 }
 648 
 649                 TALLOC_FREE(ea.value.data);
 650         }
 651 
 652         TALLOC_FREE(names);
 653         return NT_STATUS_OK;
 654 }
 655 
 656 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
     /* [<][>][^][v][top][bottom][index][help] */
 657                            struct stream_struct **streams,
 658                            const char *name, SMB_OFF_T size,
 659                            SMB_OFF_T alloc_size)
 660 {
 661         struct stream_struct *tmp;
 662 
 663         tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct,
 664                                    (*num_streams)+1);
 665         if (tmp == NULL) {
 666                 return false;
 667         }
 668 
 669         tmp[*num_streams].name = talloc_strdup(tmp, name);
 670         if (tmp[*num_streams].name == NULL) {
 671                 return false;
 672         }
 673 
 674         tmp[*num_streams].size = size;
 675         tmp[*num_streams].alloc_size = alloc_size;
 676 
 677         *streams = tmp;
 678         *num_streams += 1;
 679         return true;
 680 }
 681 
 682 struct streaminfo_state {
 683         TALLOC_CTX *mem_ctx;
 684         vfs_handle_struct *handle;
 685         unsigned int num_streams;
 686         struct stream_struct *streams;
 687         NTSTATUS status;
 688 };
 689 
 690 static bool collect_one_stream(struct ea_struct *ea, void *private_data)
     /* [<][>][^][v][top][bottom][index][help] */
 691 {
 692         struct streaminfo_state *state =
 693                 (struct streaminfo_state *)private_data;
 694 
 695         if (!add_one_stream(state->mem_ctx,
 696                             &state->num_streams, &state->streams,
 697                             ea->name, ea->value.length-1,
 698                             smb_roundup(state->handle->conn,
 699                                         ea->value.length-1))) {
 700                 state->status = NT_STATUS_NO_MEMORY;
 701                 return false;
 702         }
 703 
 704         return true;
 705 }
 706 
 707 static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 708                                          struct files_struct *fsp,
 709                                          const char *fname,
 710                                          TALLOC_CTX *mem_ctx,
 711                                          unsigned int *pnum_streams,
 712                                          struct stream_struct **pstreams)
 713 {
 714         SMB_STRUCT_STAT sbuf;
 715         int ret;
 716         NTSTATUS status;
 717         struct streaminfo_state state;
 718 
 719         if ((fsp != NULL) && (fsp->fh->fd != -1)) {
 720                 if (is_ntfs_stream_name(fsp->fsp_name)) {
 721                         return NT_STATUS_INVALID_PARAMETER;
 722                 }
 723                 ret = SMB_VFS_FSTAT(fsp, &sbuf);
 724         }
 725         else {
 726                 if (is_ntfs_stream_name(fname)) {
 727                         return NT_STATUS_INVALID_PARAMETER;
 728                 }
 729                 if (lp_posix_pathnames()) {
 730                         ret = SMB_VFS_LSTAT(handle->conn, fname, &sbuf);
 731                 } else {
 732                         ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
 733                 }
 734         }
 735 
 736         if (ret == -1) {
 737                 return map_nt_error_from_unix(errno);
 738         }
 739 
 740         state.streams = NULL;
 741         state.num_streams = 0;
 742 
 743         if (!S_ISDIR(sbuf.st_mode)) {
 744                 if (!add_one_stream(mem_ctx,
 745                                     &state.num_streams, &state.streams,
 746                                     "::$DATA", sbuf.st_size,
 747                                     SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp,
 748                                                            &sbuf))) {
 749                         return NT_STATUS_NO_MEMORY;
 750                 }
 751         }
 752 
 753         state.mem_ctx = mem_ctx;
 754         state.handle = handle;
 755         state.status = NT_STATUS_OK;
 756 
 757         status = walk_xattr_streams(handle->conn, fsp, fname,
 758                                     collect_one_stream, &state);
 759 
 760         if (!NT_STATUS_IS_OK(status)) {
 761                 TALLOC_FREE(state.streams);
 762                 return status;
 763         }
 764 
 765         if (!NT_STATUS_IS_OK(state.status)) {
 766                 TALLOC_FREE(state.streams);
 767                 return state.status;
 768         }
 769 
 770         *pnum_streams = state.num_streams;
 771         *pstreams = state.streams;
 772         return NT_STATUS_OK;
 773 }
 774 
 775 static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle)
     /* [<][>][^][v][top][bottom][index][help] */
 776 {
 777         return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
 778 }
 779 
 780 static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 781                                     files_struct *fsp, const void *data,
 782                                     size_t n, SMB_OFF_T offset)
 783 {
 784         struct stream_io *sio =
 785                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
 786         struct ea_struct ea;
 787         NTSTATUS status;
 788         int ret;
 789 
 790         DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n));
 791 
 792         if (sio == NULL) {
 793                 return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
 794         }
 795 
 796         if (!streams_xattr_recheck(sio)) {
 797                 return -1;
 798         }
 799 
 800         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
 801                               sio->base, sio->xattr_name, &ea);
 802         if (!NT_STATUS_IS_OK(status)) {
 803                 return -1;
 804         }
 805 
 806         if ((offset + n) > ea.value.length-1) {
 807                 uint8 *tmp;
 808 
 809                 tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
 810                                            offset + n + 1);
 811 
 812                 if (tmp == NULL) {
 813                         TALLOC_FREE(ea.value.data);
 814                         errno = ENOMEM;
 815                         return -1;
 816                 }
 817                 ea.value.data = tmp;
 818                 ea.value.length = offset + n + 1;
 819                 ea.value.data[offset+n] = 0;
 820         }
 821 
 822         memcpy(ea.value.data + offset, data, n);
 823 
 824         if (fsp->base_fsp->fh->fd != -1) {
 825                 ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
 826                                 sio->xattr_name,
 827                                 ea.value.data, ea.value.length, 0);
 828         } else {
 829                 ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
 830                                 sio->xattr_name,
 831                                 ea.value.data, ea.value.length, 0);
 832         }
 833         TALLOC_FREE(ea.value.data);
 834 
 835         if (ret == -1) {
 836                 return -1;
 837         }
 838 
 839         return n;
 840 }
 841 
 842 static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 843                                    files_struct *fsp, void *data,
 844                                    size_t n, SMB_OFF_T offset)
 845 {
 846         struct stream_io *sio =
 847                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
 848         struct ea_struct ea;
 849         NTSTATUS status;
 850         size_t length, overlap;
 851 
 852         if (sio == NULL) {
 853                 return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
 854         }
 855 
 856         if (!streams_xattr_recheck(sio)) {
 857                 return -1;
 858         }
 859 
 860         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
 861                               sio->base, sio->xattr_name, &ea);
 862         if (!NT_STATUS_IS_OK(status)) {
 863                 return -1;
 864         }
 865 
 866         length = ea.value.length-1;
 867 
 868         /* Attempt to read past EOF. */
 869         if (length <= offset) {
 870                 return 0;
 871         }
 872 
 873         overlap = (offset + n) > length ? (length - offset) : n;
 874         memcpy(data, ea.value.data + offset, overlap);
 875 
 876         TALLOC_FREE(ea.value.data);
 877         return overlap;
 878 }
 879 
 880 static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 881                                         struct files_struct *fsp,
 882                                         SMB_OFF_T offset)
 883 {
 884         int ret;
 885         uint8 *tmp;
 886         struct ea_struct ea;
 887         NTSTATUS status;
 888         struct stream_io *sio =
 889                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
 890 
 891         DEBUG(10, ("streams_xattr_ftruncate called for file %s offset %.0f\n",
 892                 fsp->fsp_name,
 893                 (double)offset ));
 894 
 895         if (sio == NULL) {
 896                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
 897         }
 898 
 899         if (!streams_xattr_recheck(sio)) {
 900                 return -1;
 901         }
 902 
 903         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
 904                               sio->base, sio->xattr_name, &ea);
 905         if (!NT_STATUS_IS_OK(status)) {
 906                 return -1;
 907         }
 908 
 909         tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
 910                                    offset + 1);
 911 
 912         if (tmp == NULL) {
 913                 TALLOC_FREE(ea.value.data);
 914                 errno = ENOMEM;
 915                 return -1;
 916         }
 917 
 918         /* Did we expand ? */
 919         if (ea.value.length < offset + 1) {
 920                 memset(&tmp[ea.value.length], '\0',
 921                         offset + 1 - ea.value.length);
 922         }
 923 
 924         ea.value.data = tmp;
 925         ea.value.length = offset + 1;
 926         ea.value.data[offset] = 0;
 927 
 928         if (fsp->base_fsp->fh->fd != -1) {
 929                 ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
 930                                 sio->xattr_name,
 931                                 ea.value.data, ea.value.length, 0);
 932         } else {
 933                 ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
 934                                 sio->xattr_name,
 935                                 ea.value.data, ea.value.length, 0);
 936         }
 937 
 938         TALLOC_FREE(ea.value.data);
 939 
 940         if (ret == -1) {
 941                 return -1;
 942         }
 943 
 944         return 0;
 945 }
 946 
 947 /* VFS operations structure */
 948 
 949 static vfs_op_tuple streams_xattr_ops[] = {
 950         {SMB_VFS_OP(streams_xattr_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
 951          SMB_VFS_LAYER_TRANSPARENT},
 952         {SMB_VFS_OP(streams_xattr_open), SMB_VFS_OP_OPEN,
 953          SMB_VFS_LAYER_TRANSPARENT},
 954         {SMB_VFS_OP(streams_xattr_stat), SMB_VFS_OP_STAT,
 955          SMB_VFS_LAYER_TRANSPARENT},
 956         {SMB_VFS_OP(streams_xattr_fstat), SMB_VFS_OP_FSTAT,
 957          SMB_VFS_LAYER_TRANSPARENT},
 958         {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT,
 959          SMB_VFS_LAYER_TRANSPARENT},
 960         {SMB_VFS_OP(streams_xattr_pread), SMB_VFS_OP_PREAD,
 961          SMB_VFS_LAYER_TRANSPARENT},
 962         {SMB_VFS_OP(streams_xattr_pwrite), SMB_VFS_OP_PWRITE,
 963          SMB_VFS_LAYER_TRANSPARENT},
 964         {SMB_VFS_OP(streams_xattr_unlink), SMB_VFS_OP_UNLINK,
 965          SMB_VFS_LAYER_TRANSPARENT},
 966         {SMB_VFS_OP(streams_xattr_rename), SMB_VFS_OP_RENAME,
 967          SMB_VFS_LAYER_TRANSPARENT},
 968         {SMB_VFS_OP(streams_xattr_ftruncate),  SMB_VFS_OP_FTRUNCATE,
 969          SMB_VFS_LAYER_TRANSPARENT},
 970         {SMB_VFS_OP(streams_xattr_streaminfo), SMB_VFS_OP_STREAMINFO,
 971          SMB_VFS_LAYER_OPAQUE},
 972         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
 973 };
 974 
 975 NTSTATUS vfs_streams_xattr_init(void);
 976 NTSTATUS vfs_streams_xattr_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 977 {
 978         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_xattr",
 979                                 streams_xattr_ops);
 980 }

/* [<][>][^][v][top][bottom][index][help] */