root/source3/modules/onefs_streams.c

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

DEFINITIONS

This source file includes following definitions.
  1. onefs_split_ntfs_stream_name
  2. onefs_is_stream
  3. onefs_close
  4. get_stream_dir_fd
  5. onefs_rename
  6. merge_stat
  7. onefs_adjust_stat_time
  8. stat_stream
  9. onefs_stat
  10. onefs_fstat
  11. onefs_lstat
  12. onefs_unlink
  13. onefs_vtimes_streams
  14. onefs_chflags
  15. add_one_stream
  16. walk_onefs_streams
  17. onefs_streaminfo

   1 /*
   2  * Unix SMB/CIFS implementation.
   3  *
   4  * Support for OneFS Alternate Data Streams
   5  *
   6  * Copyright (C) Tim Prouty, 2008
   7  *
   8  * This program is free software; you can redistribute it and/or modify
   9  * it under the terms of the GNU General Public License as published by
  10  * the Free Software Foundation; either version 3 of the License, or
  11  * (at your option) any later version.
  12  *
  13  * This program is distributed in the hope that it will be useful,
  14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16  * GNU General Public License for more details.
  17  *
  18  * You should have received a copy of the GNU General Public License
  19  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  20  */
  21 
  22 #include "includes.h"
  23 #include "onefs.h"
  24 #include "onefs_config.h"
  25 
  26 #include <sys/isi_enc.h>
  27 
  28 /*
  29  * OneFS stores streams without the explicit :$DATA at the end, so this strips
  30  * it off.  All onefs_stream functions must call through this instead of
  31  * split_ntfs_stream_name directly.
  32  */
  33 NTSTATUS onefs_split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
  34                                       char **pbase, char **pstream)
  35 {
  36         NTSTATUS status;
  37         char *stream;
  38 
  39         status = split_ntfs_stream_name(mem_ctx, fname, pbase, pstream);
  40         if (!NT_STATUS_IS_OK(status)) {
  41                 return status;
  42         }
  43 
  44         /* Default $DATA stream.  */
  45         if (pstream == NULL || *pstream == NULL) {
  46                 return NT_STATUS_OK;
  47         }
  48 
  49         /* Strip off the $DATA. */
  50         stream = strrchr_m(*pstream, ':');
  51         SMB_ASSERT(stream);
  52         stream[0] = '\0';
  53 
  54         return NT_STATUS_OK;
  55 }
  56 
  57 int onefs_is_stream(const char *path, char **pbase, char **pstream,
     /* [<][>][^][v][top][bottom][index][help] */
  58                     bool *is_stream)
  59 {
  60         (*is_stream) = is_ntfs_stream_name(path);
  61 
  62         if (!(*is_stream)) {
  63                 return 0;
  64         }
  65 
  66         if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), path,
  67                                                           pbase, pstream))) {
  68                 DEBUG(10, ("onefs_split_ntfs_stream_name failed\n"));
  69                 errno = ENOMEM;
  70                 return -1;
  71         }
  72 
  73         return 0;
  74 }
  75 
  76 int onefs_close(vfs_handle_struct *handle, struct files_struct *fsp)
     /* [<][>][^][v][top][bottom][index][help] */
  77 {
  78         int ret2, ret = 0;
  79 
  80         if (fsp->base_fsp) {
  81                 ret = SMB_VFS_NEXT_CLOSE(handle, fsp->base_fsp);
  82         }
  83         ret2 = SMB_VFS_NEXT_CLOSE(handle, fsp);
  84 
  85         return ret ? ret : ret2;
  86 }
  87 
  88 /*
  89  * Get the ADS directory fd for a file.
  90  */
  91 static int get_stream_dir_fd(connection_struct *conn, const char *base,
     /* [<][>][^][v][top][bottom][index][help] */
  92                              int *base_fdp)
  93 {
  94         int base_fd;
  95         int dir_fd;
  96         int saved_errno;
  97 
  98         /* If a valid base_fdp was given, use it. */
  99         if (base_fdp && *base_fdp >= 0) {
 100                 base_fd = *base_fdp;
 101         } else {
 102                 base_fd = onefs_sys_create_file(conn,
 103                                                 -1,
 104                                                 base,
 105                                                 0,
 106                                                 0,
 107                                                 0,
 108                                                 0,
 109                                                 0,
 110                                                 0,
 111                                                 INTERNAL_OPEN_ONLY,
 112                                                 0,
 113                                                 NULL,
 114                                                 0,
 115                                                 NULL);
 116                 if (base_fd < 0) {
 117                         return -1;
 118                 }
 119         }
 120 
 121         /* Open the ADS directory. */
 122         dir_fd = onefs_sys_create_file(conn,
 123                                         base_fd,
 124                                         ".",
 125                                         0,
 126                                         FILE_READ_DATA,
 127                                         0,
 128                                         0,
 129                                         0,
 130                                         0,
 131                                         INTERNAL_OPEN_ONLY,
 132                                         0,
 133                                         NULL,
 134                                         0,
 135                                         NULL);
 136 
 137         /* Close base_fd if it's not need or on error. */
 138         if (!base_fdp || dir_fd < 0) {
 139                 saved_errno = errno;
 140                 close(base_fd);
 141                 errno = saved_errno;
 142         }
 143 
 144         /* Set the out base_fdp if successful and it was requested. */
 145         if (base_fdp && dir_fd >= 0) {
 146                 *base_fdp = base_fd;
 147         }
 148 
 149         return dir_fd;
 150 }
 151 
 152 int onefs_rename(vfs_handle_struct *handle, const char *oldname,
     /* [<][>][^][v][top][bottom][index][help] */
 153                  const char *newname)
 154 {
 155         TALLOC_CTX *frame = NULL;
 156         int ret = -1;
 157         int dir_fd = -1;
 158         int saved_errno;
 159         bool old_is_stream;
 160         bool new_is_stream;
 161         char *obase = NULL;
 162         char *osname = NULL;
 163         char *nbase = NULL;
 164         char *nsname = NULL;
 165 
 166         START_PROFILE(syscall_rename_at);
 167 
 168         frame = talloc_stackframe();
 169 
 170         ret = onefs_is_stream(oldname, &obase, &osname, &old_is_stream);
 171         if (ret) {
 172                 END_PROFILE(syscall_rename_at);
 173                 return ret;
 174         }
 175 
 176         ret = onefs_is_stream(newname, &nbase, &nsname, &new_is_stream);
 177         if (ret) {
 178                 END_PROFILE(syscall_rename_at);
 179                 return ret;
 180         }
 181 
 182         if (!old_is_stream && !new_is_stream) {
 183                 ret = SMB_VFS_NEXT_RENAME(handle, oldname, newname);
 184                 END_PROFILE(syscall_rename_at);
 185                 return ret;
 186         }
 187 
 188         dir_fd = get_stream_dir_fd(handle->conn, obase, NULL);
 189         if (dir_fd < -1) {
 190                 goto done;
 191         }
 192 
 193         DEBUG(8,("onefs_rename called for %s : %s  => %s : %s\n",
 194                 obase, osname,  nbase, nsname));
 195 
 196         /* Handle rename of stream to default stream specially. */
 197         if (nsname == NULL) {
 198                 ret = enc_renameat(dir_fd, osname, ENC_DEFAULT, AT_FDCWD,
 199                                    nbase, ENC_DEFAULT);
 200         } else {
 201                 ret = enc_renameat(dir_fd, osname, ENC_DEFAULT, dir_fd, nsname,
 202                                    ENC_DEFAULT);
 203         }
 204 
 205  done:
 206         END_PROFILE(syscall_rename_at);
 207 
 208         saved_errno = errno;
 209         if (dir_fd >= 0) {
 210                 close(dir_fd);
 211         }
 212         errno = saved_errno;
 213         TALLOC_FREE(frame);
 214         return ret;
 215 }
 216 
 217 /*
 218  * Merge a base file's sbuf into the a streams's sbuf.
 219  */
 220 static void merge_stat(SMB_STRUCT_STAT *stream_sbuf,
     /* [<][>][^][v][top][bottom][index][help] */
 221                        const SMB_STRUCT_STAT *base_sbuf)
 222 {
 223         int dos_flags = (UF_DOS_NOINDEX | UF_DOS_ARCHIVE |
 224             UF_DOS_HIDDEN | UF_DOS_RO | UF_DOS_SYSTEM);
 225         stream_sbuf->st_mtime = base_sbuf->st_mtime;
 226         stream_sbuf->st_ctime = base_sbuf->st_ctime;
 227         stream_sbuf->st_atime = base_sbuf->st_atime;
 228         stream_sbuf->st_flags &= ~dos_flags;
 229         stream_sbuf->st_flags |= base_sbuf->st_flags & dos_flags;
 230 }
 231 
 232 /* fake timestamps */
 233 static void onefs_adjust_stat_time(vfs_handle_struct *handle, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 234                                    SMB_STRUCT_STAT *sbuf)
 235 {
 236         struct onefs_vfs_share_config cfg;
 237         struct timeval tv_now = {0, 0};
 238         bool static_mtime = False;
 239         bool static_atime = False;
 240 
 241         if (!onefs_get_config(SNUM(handle->conn),
 242                               ONEFS_VFS_CONFIG_FAKETIMESTAMPS, &cfg)) {
 243                 return;
 244         }
 245 
 246         if (IS_MTIME_STATIC_PATH(handle->conn, &cfg, fname)) {
 247                 sbuf->st_mtime = sbuf->st_birthtime;
 248                 static_mtime = True;
 249         }
 250         if (IS_ATIME_STATIC_PATH(handle->conn, &cfg, fname)) {
 251                 sbuf->st_atime = sbuf->st_birthtime;
 252                 static_atime = True;
 253         }
 254 
 255         if (IS_CTIME_NOW_PATH(handle->conn, &cfg, fname)) {
 256                 if (cfg.ctime_slop < 0) {
 257                         sbuf->st_birthtime = INT_MAX - 1;
 258                 } else {
 259                         GetTimeOfDay(&tv_now);
 260                         sbuf->st_birthtime = tv_now.tv_sec + cfg.ctime_slop;
 261                 }
 262         }
 263 
 264         if (!static_mtime && IS_MTIME_NOW_PATH(handle->conn,&cfg,fname)) {
 265                 if (cfg.mtime_slop < 0) {
 266                         sbuf->st_mtime = INT_MAX - 1;
 267                 } else {
 268                         if (tv_now.tv_sec == 0)
 269                                 GetTimeOfDay(&tv_now);
 270                         sbuf->st_mtime = tv_now.tv_sec + cfg.mtime_slop;
 271                 }
 272         }
 273         if (!static_atime && IS_ATIME_NOW_PATH(handle->conn,&cfg,fname)) {
 274                 if (cfg.atime_slop < 0) {
 275                         sbuf->st_atime = INT_MAX - 1;
 276                 } else {
 277                         if (tv_now.tv_sec == 0)
 278                                 GetTimeOfDay(&tv_now);
 279                         sbuf->st_atime = tv_now.tv_sec + cfg.atime_slop;
 280                 }
 281         }
 282 }
 283 
 284 static int stat_stream(vfs_handle_struct *handle, const char *base,
     /* [<][>][^][v][top][bottom][index][help] */
 285                        const char *stream, SMB_STRUCT_STAT *sbuf, int flags)
 286 {
 287         SMB_STRUCT_STAT base_sbuf;
 288         int base_fd = -1, dir_fd, ret, saved_errno;
 289 
 290         dir_fd = get_stream_dir_fd(handle->conn, base, &base_fd);
 291         if (dir_fd < 0) {
 292                 return -1;
 293         }
 294 
 295         /* Stat the stream. */
 296         ret = enc_fstatat(dir_fd, stream, ENC_DEFAULT, sbuf, flags);
 297         if (ret != -1) {
 298                 /* Now stat the base file and merge the results. */
 299                 ret = sys_fstat(base_fd, &base_sbuf);
 300                 if (ret != -1) {
 301                         merge_stat(sbuf, &base_sbuf);
 302                 }
 303         }
 304 
 305         saved_errno = errno;
 306         close(dir_fd);
 307         close(base_fd);
 308         errno = saved_errno;
 309         return ret;
 310 }
 311 
 312 int onefs_stat(vfs_handle_struct *handle, const char *path,
     /* [<][>][^][v][top][bottom][index][help] */
 313                SMB_STRUCT_STAT *sbuf)
 314 {
 315         int ret;
 316         bool is_stream;
 317         char *base = NULL;
 318         char *stream = NULL;
 319 
 320         ret = onefs_is_stream(path, &base, &stream, &is_stream);
 321         if (ret)
 322                 return ret;
 323 
 324         if (!is_stream) {
 325                 ret = SMB_VFS_NEXT_STAT(handle, path, sbuf);
 326         } else if (!stream) {
 327                 /* If it's the ::$DATA stream just stat the base file name. */
 328                 ret = SMB_VFS_NEXT_STAT(handle, base, sbuf);
 329         } else {
 330                 ret = stat_stream(handle, base, stream, sbuf, 0);
 331         }
 332 
 333         onefs_adjust_stat_time(handle, path, sbuf);
 334         return ret;
 335 }
 336 
 337 int onefs_fstat(vfs_handle_struct *handle, struct files_struct *fsp,
     /* [<][>][^][v][top][bottom][index][help] */
 338                 SMB_STRUCT_STAT *sbuf)
 339 {
 340         SMB_STRUCT_STAT base_sbuf;
 341         int ret;
 342 
 343         /* Stat the stream, by calling next_fstat on the stream's fd. */
 344         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
 345         if (ret == -1) {
 346                 return ret;
 347         }
 348 
 349         /* Stat the base file and merge the results. */
 350         if (fsp != NULL && fsp->base_fsp != NULL) {
 351                 ret = sys_fstat(fsp->base_fsp->fh->fd, &base_sbuf);
 352                 if (ret != -1) {
 353                         merge_stat(sbuf, &base_sbuf);
 354                 }
 355         }
 356 
 357         onefs_adjust_stat_time(handle, fsp->fsp_name, sbuf);
 358         return ret;
 359 }
 360 
 361 int onefs_lstat(vfs_handle_struct *handle, const char *path,
     /* [<][>][^][v][top][bottom][index][help] */
 362                 SMB_STRUCT_STAT *sbuf)
 363 {
 364         int ret;
 365         bool is_stream;
 366         char *base = NULL;
 367         char *stream = NULL;
 368 
 369         ret = onefs_is_stream(path, &base, &stream, &is_stream);
 370         if (ret)
 371                 return ret;
 372 
 373         if (!is_stream) {
 374                 ret = SMB_VFS_NEXT_LSTAT(handle, path, sbuf);
 375         } else if (!stream) {
 376                 /* If it's the ::$DATA stream just stat the base file name. */
 377                 ret = SMB_VFS_NEXT_LSTAT(handle, base, sbuf);
 378         } else {
 379                 ret = stat_stream(handle, base, stream, sbuf,
 380                                   AT_SYMLINK_NOFOLLOW);
 381         }
 382 
 383         onefs_adjust_stat_time(handle, path, sbuf);
 384         return ret;
 385 }
 386 
 387 int onefs_unlink(vfs_handle_struct *handle, const char *path)
     /* [<][>][^][v][top][bottom][index][help] */
 388 {
 389         int ret;
 390         bool is_stream;
 391         char *base = NULL;
 392         char *stream = NULL;
 393         int dir_fd, saved_errno;
 394 
 395         ret = onefs_is_stream(path, &base, &stream, &is_stream);
 396         if (ret) {
 397                 return ret;
 398         }
 399 
 400         if (!is_stream) {
 401                 return SMB_VFS_NEXT_UNLINK(handle, path);
 402         }
 403 
 404         /* If it's the ::$DATA stream just unlink the base file name. */
 405         if (!stream) {
 406                 return SMB_VFS_NEXT_UNLINK(handle, base);
 407         }
 408 
 409         dir_fd = get_stream_dir_fd(handle->conn, base, NULL);
 410         if (dir_fd < 0) {
 411                 return -1;
 412         }
 413 
 414         ret = enc_unlinkat(dir_fd, stream, ENC_DEFAULT, 0);
 415 
 416         saved_errno = errno;
 417         close(dir_fd);
 418         errno = saved_errno;
 419         return ret;
 420 }
 421 
 422 int onefs_vtimes_streams(vfs_handle_struct *handle, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 423                          int flags, struct timespec times[3])
 424 {
 425         int ret;
 426         bool is_stream;
 427         char *base;
 428         char *stream;
 429         int dirfd;
 430         int saved_errno;
 431 
 432         START_PROFILE(syscall_ntimes);
 433 
 434         ret = onefs_is_stream(fname, &base, &stream, &is_stream);
 435         if (ret)
 436                 return ret;
 437 
 438         if (!is_stream) {
 439                 ret = vtimes(fname, times, flags);
 440                 return ret;
 441         }
 442 
 443         dirfd = get_stream_dir_fd(handle->conn, base, NULL);
 444         if (dirfd < -1) {
 445                 return -1;
 446         }
 447 
 448         ret = enc_vtimesat(dirfd, stream, ENC_DEFAULT, times, flags);
 449 
 450         END_PROFILE(syscall_ntimes);
 451 
 452         saved_errno = errno;
 453         close(dirfd);
 454         errno = saved_errno;
 455         return ret;
 456 }
 457 
 458 int onefs_chflags(vfs_handle_struct *handle, const char *path,
     /* [<][>][^][v][top][bottom][index][help] */
 459                   unsigned int flags)
 460 {
 461         char *base = NULL;
 462         char *stream = NULL;
 463 
 464         if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), path,
 465                                                           &base, &stream))) {
 466                 DEBUG(10, ("onefs_split_ntfs_stream_name failed\n"));
 467                 errno = ENOMEM;
 468                 return -1;
 469         }
 470 
 471         /*
 472          * Only set the attributes on the base file.  ifs_createfile handles
 473          * file creation attribute semantics.
 474          */
 475         return SMB_VFS_NEXT_CHFLAGS(handle, base, flags);
 476 }
 477 
 478 /*
 479  * Streaminfo enumeration functionality
 480  */
 481 struct streaminfo_state {
 482         TALLOC_CTX *mem_ctx;
 483         vfs_handle_struct *handle;
 484         unsigned int num_streams;
 485         struct stream_struct *streams;
 486         NTSTATUS status;
 487 };
 488 
 489 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
     /* [<][>][^][v][top][bottom][index][help] */
 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_asprintf(mem_ctx, ":%s:%s", name,
 503                                                  "$DATA");
 504         if (tmp[*num_streams].name == NULL) {
 505                 return false;
 506         }
 507 
 508         tmp[*num_streams].size = size;
 509         tmp[*num_streams].alloc_size = alloc_size;
 510 
 511         *streams = tmp;
 512         *num_streams += 1;
 513         return true;
 514 }
 515 
 516 static NTSTATUS walk_onefs_streams(connection_struct *conn, files_struct *fsp,
     /* [<][>][^][v][top][bottom][index][help] */
 517                                    const char *fname,
 518                                    struct streaminfo_state *state,
 519                                    SMB_STRUCT_STAT *base_sbuf)
 520 {
 521         NTSTATUS status = NT_STATUS_OK;
 522         bool opened_base_fd = false;
 523         int base_fd = -1;
 524         int dir_fd = -1;
 525         int stream_fd = -1;
 526         int ret;
 527         SMB_STRUCT_DIR *dirp = NULL;
 528         SMB_STRUCT_DIRENT *dp = NULL;
 529         files_struct fake_fs;
 530         struct fd_handle fake_fh;
 531         SMB_STRUCT_STAT stream_sbuf;
 532 
 533         ZERO_STRUCT(fake_fh);
 534         ZERO_STRUCT(fake_fs);
 535 
 536         /* If the base file is already open, use its fd. */
 537         if ((fsp != NULL) && (fsp->fh->fd != -1)) {
 538                 base_fd = fsp->fh->fd;
 539         } else {
 540                 opened_base_fd = true;
 541         }
 542 
 543         dir_fd = get_stream_dir_fd(conn, fname, &base_fd);
 544         if (dir_fd < 0) {
 545                 return map_nt_error_from_unix(errno);
 546         }
 547 
 548         /* Open the ADS directory. */
 549         if ((dirp = fdopendir(dir_fd)) == NULL) {
 550                 DEBUG(0, ("Error on opendir %s. errno=%d (%s)\n",
 551                           fname, errno, strerror(errno)));
 552                 status = map_nt_error_from_unix(errno);
 553                 goto out;
 554         }
 555 
 556         /* Initialize the dir state struct and add it to the list.
 557          * This is a layer violation, and really should be handled by a
 558          * VFS_FDOPENDIR() call which would properly setup the dir state.
 559          * But since this is all within the onefs.so module, we cheat for
 560          * now and call directly into the readdirplus code.
 561          * NOTE: This state MUST be freed by a proper VFS_CLOSEDIR() call. */
 562         ret = onefs_rdp_add_dir_state(conn, dirp);
 563         if (ret) {
 564                 DEBUG(0, ("Error adding dir_state to the list\n"));
 565                 status = map_nt_error_from_unix(errno);
 566                 goto out;
 567         }
 568 
 569         fake_fs.conn = conn;
 570         fake_fs.fh = &fake_fh;
 571         fake_fs.fsp_name = SMB_STRDUP(fname);
 572 
 573         /* Iterate over the streams in the ADS directory. */
 574         while ((dp = SMB_VFS_READDIR(conn, dirp, NULL)) != NULL) {
 575                 /* Skip the "." and ".." entries */
 576                 if ((strcmp(dp->d_name, ".") == 0) ||
 577                     (strcmp(dp->d_name, "..") == 0))
 578                         continue;
 579 
 580                 /* Open actual stream */
 581                 if ((stream_fd = onefs_sys_create_file(conn,
 582                                                          base_fd,
 583                                                          dp->d_name,
 584                                                          0,
 585                                                          0,
 586                                                          0,
 587                                                          0,
 588                                                          0,
 589                                                          0,
 590                                                          INTERNAL_OPEN_ONLY,
 591                                                          0,
 592                                                          NULL,
 593                                                          0,
 594                                                          NULL)) == -1) {
 595                         DEBUG(0, ("Error opening stream %s:%s. "
 596                                   "errno=%d (%s)\n", fname, dp->d_name, errno,
 597                                   strerror(errno)));
 598                         continue;
 599                 }
 600 
 601                 /* Figure out the stat info. */
 602                 fake_fh.fd = stream_fd;
 603                 ret = SMB_VFS_FSTAT(&fake_fs, &stream_sbuf);
 604                 close(stream_fd);
 605 
 606                 if (ret) {
 607                         DEBUG(0, ("Error fstating stream %s:%s. "
 608                                   "errno=%d (%s)\n", fname, dp->d_name, errno,
 609                                   strerror(errno)));
 610                         continue;
 611                 }
 612 
 613                 merge_stat(&stream_sbuf, base_sbuf);
 614 
 615                 if (!add_one_stream(state->mem_ctx,
 616                                     &state->num_streams, &state->streams,
 617                                     dp->d_name, stream_sbuf.st_size,
 618                                     SMB_VFS_GET_ALLOC_SIZE(conn, NULL,
 619                                                            &stream_sbuf))) {
 620                         state->status = NT_STATUS_NO_MEMORY;
 621                         break;
 622                 }
 623         }
 624 
 625 out:
 626         /* Cleanup everything that was opened. */
 627         if (dirp != NULL) {
 628                 SMB_VFS_CLOSEDIR(conn, dirp);
 629         }
 630         if (dir_fd >= 0) {
 631                 close(dir_fd);
 632         }
 633         if (opened_base_fd) {
 634                 SMB_ASSERT(base_fd >= 0);
 635                 close(base_fd);
 636         }
 637 
 638         SAFE_FREE(fake_fs.fsp_name);
 639         return status;
 640 }
 641 
 642 NTSTATUS onefs_streaminfo(vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 643                           struct files_struct *fsp,
 644                           const char *fname,
 645                           TALLOC_CTX *mem_ctx,
 646                           unsigned int *num_streams,
 647                           struct stream_struct **streams)
 648 {
 649         SMB_STRUCT_STAT sbuf;
 650         int ret;
 651         NTSTATUS status;
 652         struct streaminfo_state state;
 653 
 654         /* Get a valid stat. */
 655         if ((fsp != NULL) && (fsp->fh->fd != -1)) {
 656                 if (is_ntfs_stream_name(fsp->fsp_name)) {
 657                         return NT_STATUS_INVALID_PARAMETER;
 658                 }
 659                 ret = SMB_VFS_FSTAT(fsp, &sbuf);
 660         } else {
 661                 if (is_ntfs_stream_name(fname)) {
 662                         return NT_STATUS_INVALID_PARAMETER;
 663                 }
 664                 ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
 665         }
 666 
 667         if (ret == -1) {
 668                 return map_nt_error_from_unix(errno);
 669         }
 670 
 671         state.streams = NULL;
 672         state.num_streams = 0;
 673 
 674         if (lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE,
 675                 PARM_IGNORE_STREAMS, PARM_IGNORE_STREAMS_DEFAULT)) {
 676                 goto out;
 677         }
 678 
 679         /* Add the default stream. */
 680         if (S_ISREG(sbuf.st_mode)) {
 681                 if (!add_one_stream(mem_ctx,
 682                                     &state.num_streams, &state.streams,
 683                                     "", sbuf.st_size,
 684                                     SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp,
 685                                                            &sbuf))) {
 686                         return NT_STATUS_NO_MEMORY;
 687                 }
 688         }
 689 
 690         state.mem_ctx = mem_ctx;
 691         state.handle = handle;
 692         state.status = NT_STATUS_OK;
 693 
 694         /* If there are more streams, add them too. */
 695         if (sbuf.st_flags & UF_HASADS) {
 696 
 697                 status = walk_onefs_streams(handle->conn, fsp, fname,
 698                     &state, &sbuf);
 699 
 700                 if (!NT_STATUS_IS_OK(status)) {
 701                         TALLOC_FREE(state.streams);
 702                         return status;
 703                 }
 704 
 705                 if (!NT_STATUS_IS_OK(state.status)) {
 706                         TALLOC_FREE(state.streams);
 707                         return state.status;
 708                 }
 709         }
 710  out:
 711         *num_streams = state.num_streams;
 712         *streams = state.streams;
 713         return NT_STATUS_OK;
 714 }

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