root/source4/ntvfs/simple/vfs_simple.c

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

DEFINITIONS

This source file includes following definitions.
  1. svfs_connect
  2. svfs_disconnect
  3. find_fd
  4. svfs_unlink
  5. svfs_ioctl
  6. svfs_chkpath
  7. svfs_file_id
  8. svfs_map_fileinfo
  9. svfs_qpathinfo
  10. svfs_qfileinfo
  11. svfs_open
  12. svfs_mkdir
  13. svfs_rmdir
  14. svfs_rename
  15. svfs_copy
  16. svfs_read
  17. svfs_write
  18. svfs_seek
  19. svfs_flush
  20. svfs_close
  21. svfs_exit
  22. svfs_logoff
  23. svfs_async_setup
  24. svfs_cancel
  25. svfs_lock
  26. svfs_setpathinfo
  27. svfs_setfileinfo
  28. svfs_fsinfo
  29. svfs_fsattr
  30. svfs_lpq
  31. svfs_search_first
  32. svfs_search_next
  33. svfs_search_close
  34. svfs_trans
  35. ntvfs_simple_init

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    simple NTVFS filesystem backend
   5 
   6    Copyright (C) Andrew Tridgell 2003
   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   this implements a very simple NTVFS filesystem backend. 
  23   
  24   this backend largely ignores the POSIX -> CIFS mappings, just doing absolutely
  25   minimal work to give a working backend.
  26 */
  27 
  28 #include "includes.h"
  29 #include "system/dir.h"
  30 #include "system/filesys.h"
  31 #include "svfs.h"
  32 #include "system/time.h"
  33 #include "../lib/util/dlinklist.h"
  34 #include "ntvfs/ntvfs.h"
  35 #include "ntvfs/simple/proto.h"
  36 
  37 #ifndef O_DIRECTORY
  38 #define O_DIRECTORY 0
  39 #endif
  40 
  41 #define CHECK_READ_ONLY(req) do { if (share_bool_option(ntvfs->ctx->config, SHARE_READONLY, true)) return NT_STATUS_ACCESS_DENIED; } while (0)
  42 
  43 /*
  44   connect to a share - used when a tree_connect operation comes
  45   in. For a disk based backend we needs to ensure that the base
  46   directory exists (tho it doesn't need to be accessible by the user,
  47   that comes later)
  48 */
  49 static NTSTATUS svfs_connect(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
  50                              struct ntvfs_request *req, const char *sharename)
  51 {
  52         struct stat st;
  53         struct svfs_private *p;
  54         struct share_config *scfg = ntvfs->ctx->config;
  55 
  56         p = talloc(ntvfs, struct svfs_private);
  57         NT_STATUS_HAVE_NO_MEMORY(p);
  58         p->ntvfs = ntvfs;
  59         p->next_search_handle = 0;
  60         p->connectpath = talloc_strdup(p, share_string_option(scfg, SHARE_PATH, ""));
  61         p->open_files = NULL;
  62         p->search = NULL;
  63 
  64         /* the directory must exist */
  65         if (stat(p->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
  66                 DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", 
  67                          p->connectpath, sharename));
  68                 return NT_STATUS_BAD_NETWORK_NAME;
  69         }
  70 
  71         ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
  72         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
  73         ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
  74         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
  75 
  76         ntvfs->private_data = p;
  77 
  78         return NT_STATUS_OK;
  79 }
  80 
  81 /*
  82   disconnect from a share
  83 */
  84 static NTSTATUS svfs_disconnect(struct ntvfs_module_context *ntvfs)
     /* [<][>][^][v][top][bottom][index][help] */
  85 {
  86         return NT_STATUS_OK;
  87 }
  88 
  89 /*
  90   find open file handle given fd
  91 */
  92 static struct svfs_file *find_fd(struct svfs_private *sp, struct ntvfs_handle *handle)
     /* [<][>][^][v][top][bottom][index][help] */
  93 {
  94         struct svfs_file *f;
  95         void *p;
  96 
  97         p = ntvfs_handle_get_backend_data(handle, sp->ntvfs);
  98         if (!p) return NULL;
  99 
 100         f = talloc_get_type(p, struct svfs_file);
 101         if (!f) return NULL;
 102 
 103         return f;
 104 }
 105 
 106 /*
 107   delete a file - the dirtype specifies the file types to include in the search. 
 108   The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
 109 */
 110 static NTSTATUS svfs_unlink(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 111                             struct ntvfs_request *req,
 112                             union smb_unlink *unl)
 113 {
 114         char *unix_path;
 115 
 116         CHECK_READ_ONLY(req);
 117 
 118         unix_path = svfs_unix_path(ntvfs, req, unl->unlink.in.pattern);
 119 
 120         /* ignoring wildcards ... */
 121         if (unlink(unix_path) == -1) {
 122                 return map_nt_error_from_unix(errno);
 123         }
 124 
 125         return NT_STATUS_OK;
 126 }
 127 
 128 
 129 /*
 130   ioctl interface - we don't do any
 131 */
 132 static NTSTATUS svfs_ioctl(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 133                            struct ntvfs_request *req, union smb_ioctl *io)
 134 {
 135         return NT_STATUS_INVALID_PARAMETER;
 136 }
 137 
 138 /*
 139   check if a directory exists
 140 */
 141 static NTSTATUS svfs_chkpath(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 142                              struct ntvfs_request *req,
 143                              union smb_chkpath *cp)
 144 {
 145         char *unix_path;
 146         struct stat st;
 147 
 148         unix_path = svfs_unix_path(ntvfs, req, cp->chkpath.in.path);
 149 
 150         if (stat(unix_path, &st) == -1) {
 151                 return map_nt_error_from_unix(errno);
 152         }
 153 
 154         if (!S_ISDIR(st.st_mode)) {
 155                 return NT_STATUS_NOT_A_DIRECTORY;
 156         }
 157 
 158         return NT_STATUS_OK;
 159 }
 160 
 161 /*
 162   build a file_id from a stat struct
 163 */
 164 static uint64_t svfs_file_id(struct stat *st)
     /* [<][>][^][v][top][bottom][index][help] */
 165 {
 166         uint64_t ret = st->st_ino;
 167         ret <<= 32;
 168         ret |= st->st_dev;
 169         return ret;
 170 }
 171 
 172 /*
 173   approximately map a struct stat to a generic fileinfo struct
 174 */
 175 static NTSTATUS svfs_map_fileinfo(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 176                                   struct ntvfs_request *req, union smb_fileinfo *info, 
 177                                   struct stat *st, const char *unix_path)
 178 {
 179         struct svfs_dir *dir = NULL;
 180         char *pattern = NULL;
 181         int i;
 182         const char *s, *short_name;
 183 
 184         s = strrchr(unix_path, '/');
 185         if (s) {
 186                 short_name = s+1;
 187         } else {
 188                 short_name = "";
 189         }
 190 
 191         asprintf(&pattern, "%s:*", unix_path);
 192         
 193         if (pattern) {
 194                 dir = svfs_list_unix(req, req, pattern);
 195         }
 196 
 197         unix_to_nt_time(&info->generic.out.create_time, st->st_ctime);
 198         unix_to_nt_time(&info->generic.out.access_time, st->st_atime);
 199         unix_to_nt_time(&info->generic.out.write_time,  st->st_mtime);
 200         unix_to_nt_time(&info->generic.out.change_time, st->st_mtime);
 201         info->generic.out.alloc_size = st->st_size;
 202         info->generic.out.size = st->st_size;
 203         info->generic.out.attrib = svfs_unix_to_dos_attrib(st->st_mode);
 204         info->generic.out.alloc_size = st->st_blksize * st->st_blocks;
 205         info->generic.out.nlink = st->st_nlink;
 206         info->generic.out.directory = S_ISDIR(st->st_mode) ? 1 : 0;
 207         info->generic.out.file_id = svfs_file_id(st);
 208         /* REWRITE: TODO stuff in here */
 209         info->generic.out.delete_pending = 0;
 210         info->generic.out.ea_size = 0;
 211         info->generic.out.num_eas = 0;
 212         info->generic.out.fname.s = talloc_strdup(req, short_name);
 213         info->generic.out.alt_fname.s = talloc_strdup(req, short_name);
 214         info->generic.out.compressed_size = 0;
 215         info->generic.out.format = 0;
 216         info->generic.out.unit_shift = 0;
 217         info->generic.out.chunk_shift = 0;
 218         info->generic.out.cluster_shift = 0;
 219         
 220         info->generic.out.access_flags = 0;
 221         info->generic.out.position = 0;
 222         info->generic.out.mode = 0;
 223         info->generic.out.alignment_requirement = 0;
 224         info->generic.out.reparse_tag = 0;
 225         info->generic.out.num_streams = 0;
 226         /* setup a single data stream */
 227         info->generic.out.num_streams = 1 + (dir?dir->count:0);
 228         info->generic.out.streams = talloc_array(req, 
 229                                                    struct stream_struct,
 230                                                    info->generic.out.num_streams);
 231         if (!info->generic.out.streams) {
 232                 return NT_STATUS_NO_MEMORY;
 233         }
 234         info->generic.out.streams[0].size = st->st_size;
 235         info->generic.out.streams[0].alloc_size = st->st_size;
 236         info->generic.out.streams[0].stream_name.s = talloc_strdup(req,"::$DATA");
 237 
 238         for (i=0;dir && i<dir->count;i++) {
 239                 s = strchr(dir->files[i].name, ':');
 240                 info->generic.out.streams[1+i].size = dir->files[i].st.st_size;
 241                 info->generic.out.streams[1+i].alloc_size = dir->files[i].st.st_size;
 242                 info->generic.out.streams[1+i].stream_name.s = s?s:dir->files[i].name;
 243         }
 244 
 245         return NT_STATUS_OK;
 246 }
 247 
 248 /*
 249   return info on a pathname
 250 */
 251 static NTSTATUS svfs_qpathinfo(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 252                                struct ntvfs_request *req, union smb_fileinfo *info)
 253 {
 254         char *unix_path;
 255         struct stat st;
 256 
 257         DEBUG(19,("svfs_qpathinfo: file %s level 0x%x\n", info->generic.in.file.path, info->generic.level));
 258         if (info->generic.level != RAW_FILEINFO_GENERIC) {
 259                 return ntvfs_map_qpathinfo(ntvfs, req, info);
 260         }
 261         
 262         unix_path = svfs_unix_path(ntvfs, req, info->generic.in.file.path);
 263         DEBUG(19,("svfs_qpathinfo: file %s\n", unix_path));
 264         if (stat(unix_path, &st) == -1) {
 265                 DEBUG(19,("svfs_qpathinfo: file %s errno=%d\n", unix_path, errno));
 266                 return map_nt_error_from_unix(errno);
 267         }
 268         DEBUG(19,("svfs_qpathinfo: file %s, stat done\n", unix_path));
 269         return svfs_map_fileinfo(ntvfs, req, info, &st, unix_path);
 270 }
 271 
 272 /*
 273   query info on a open file
 274 */
 275 static NTSTATUS svfs_qfileinfo(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 276                                struct ntvfs_request *req, union smb_fileinfo *info)
 277 {
 278         struct svfs_private *p = ntvfs->private_data;
 279         struct svfs_file *f;
 280         struct stat st;
 281 
 282         if (info->generic.level != RAW_FILEINFO_GENERIC) {
 283                 return ntvfs_map_qfileinfo(ntvfs, req, info);
 284         }
 285 
 286         f = find_fd(p, info->generic.in.file.ntvfs);
 287         if (!f) {
 288                 return NT_STATUS_INVALID_HANDLE;
 289         }
 290         
 291         if (fstat(f->fd, &st) == -1) {
 292                 return map_nt_error_from_unix(errno);
 293         }
 294 
 295         return svfs_map_fileinfo(ntvfs, req,info, &st, f->name);
 296 }
 297 
 298 
 299 /*
 300   open a file
 301 */
 302 static NTSTATUS svfs_open(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 303                           struct ntvfs_request *req, union smb_open *io)
 304 {
 305         struct svfs_private *p = ntvfs->private_data;
 306         char *unix_path;
 307         struct stat st;
 308         int fd, flags;
 309         struct svfs_file *f;
 310         int create_flags, rdwr_flags;
 311         bool readonly;
 312         NTSTATUS status;
 313         struct ntvfs_handle *handle;
 314         
 315         if (io->generic.level != RAW_OPEN_GENERIC) {
 316                 return ntvfs_map_open(ntvfs, req, io);
 317         }
 318 
 319         readonly = share_bool_option(ntvfs->ctx->config, SHARE_READONLY, SHARE_READONLY_DEFAULT);
 320         if (readonly) {
 321                 create_flags = 0;
 322                 rdwr_flags = O_RDONLY;
 323         } else {
 324                 create_flags = O_CREAT;
 325                 rdwr_flags = O_RDWR;
 326         }
 327 
 328         unix_path = svfs_unix_path(ntvfs, req, io->ntcreatex.in.fname);
 329 
 330         switch (io->generic.in.open_disposition) {
 331         case NTCREATEX_DISP_SUPERSEDE:
 332         case NTCREATEX_DISP_OVERWRITE_IF:
 333                 flags = create_flags | O_TRUNC;
 334                 break;
 335         case NTCREATEX_DISP_OPEN:
 336         case NTCREATEX_DISP_OVERWRITE:
 337                 flags = 0;
 338                 break;
 339         case NTCREATEX_DISP_CREATE:
 340                 flags = create_flags | O_EXCL;
 341                 break;
 342         case NTCREATEX_DISP_OPEN_IF:
 343                 flags = create_flags;
 344                 break;
 345         default:
 346                 flags = 0;
 347                 break;
 348         }
 349         
 350         flags |= rdwr_flags;
 351 
 352         if (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) {
 353                 flags = O_RDONLY | O_DIRECTORY;
 354                 if (readonly) {
 355                         goto do_open;
 356                 }
 357                 switch (io->generic.in.open_disposition) {
 358                 case NTCREATEX_DISP_CREATE:
 359                         if (mkdir(unix_path, 0755) == -1) {
 360                                 DEBUG(9,("svfs_open: mkdir %s errno=%d\n", unix_path, errno));
 361                                 return map_nt_error_from_unix(errno);
 362                         }
 363                         break;
 364                 case NTCREATEX_DISP_OPEN_IF:
 365                         if (mkdir(unix_path, 0755) == -1 && errno != EEXIST) {
 366                                 DEBUG(9,("svfs_open: mkdir %s errno=%d\n", unix_path, errno));
 367                                 return map_nt_error_from_unix(errno);
 368                         }
 369                         break;
 370                 }
 371         }
 372 
 373 do_open:
 374         fd = open(unix_path, flags, 0644);
 375         if (fd == -1) {
 376                 return map_nt_error_from_unix(errno);
 377         }
 378 
 379         if (fstat(fd, &st) == -1) {
 380                 DEBUG(9,("svfs_open: fstat errno=%d\n", errno));
 381                 close(fd);
 382                 return map_nt_error_from_unix(errno);
 383         }
 384 
 385         status = ntvfs_handle_new(ntvfs, req, &handle);
 386         NT_STATUS_NOT_OK_RETURN(status);
 387 
 388         f = talloc(handle, struct svfs_file);
 389         NT_STATUS_HAVE_NO_MEMORY(f);
 390         f->fd = fd;
 391         f->name = talloc_strdup(f, unix_path);
 392         NT_STATUS_HAVE_NO_MEMORY(f->name);
 393 
 394         DLIST_ADD(p->open_files, f);
 395 
 396         status = ntvfs_handle_set_backend_data(handle, ntvfs, f);
 397         NT_STATUS_NOT_OK_RETURN(status);
 398 
 399         ZERO_STRUCT(io->generic.out);
 400         
 401         unix_to_nt_time(&io->generic.out.create_time, st.st_ctime);
 402         unix_to_nt_time(&io->generic.out.access_time, st.st_atime);
 403         unix_to_nt_time(&io->generic.out.write_time,  st.st_mtime);
 404         unix_to_nt_time(&io->generic.out.change_time, st.st_mtime);
 405         io->generic.out.file.ntvfs = handle;
 406         io->generic.out.alloc_size = st.st_size;
 407         io->generic.out.size = st.st_size;
 408         io->generic.out.attrib = svfs_unix_to_dos_attrib(st.st_mode);
 409         io->generic.out.is_directory = S_ISDIR(st.st_mode) ? 1 : 0;
 410 
 411         return NT_STATUS_OK;
 412 }
 413 
 414 /*
 415   create a directory
 416 */
 417 static NTSTATUS svfs_mkdir(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 418                            struct ntvfs_request *req, union smb_mkdir *md)
 419 {
 420         char *unix_path;
 421 
 422         CHECK_READ_ONLY(req);
 423 
 424         if (md->generic.level != RAW_MKDIR_MKDIR) {
 425                 return NT_STATUS_INVALID_LEVEL;
 426         }
 427 
 428         unix_path = svfs_unix_path(ntvfs, req, md->mkdir.in.path);
 429 
 430         if (mkdir(unix_path, 0777) == -1) {
 431                 return map_nt_error_from_unix(errno);
 432         }
 433 
 434         return NT_STATUS_OK;
 435 }
 436 
 437 /*
 438   remove a directory
 439 */
 440 static NTSTATUS svfs_rmdir(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 441                            struct ntvfs_request *req, struct smb_rmdir *rd)
 442 {
 443         char *unix_path;
 444 
 445         CHECK_READ_ONLY(req);
 446 
 447         unix_path = svfs_unix_path(ntvfs, req, rd->in.path);
 448 
 449         if (rmdir(unix_path) == -1) {
 450                 return map_nt_error_from_unix(errno);
 451         }
 452 
 453         return NT_STATUS_OK;
 454 }
 455 
 456 /*
 457   rename a set of files
 458 */
 459 static NTSTATUS svfs_rename(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 460                             struct ntvfs_request *req, union smb_rename *ren)
 461 {
 462         char *unix_path1, *unix_path2;
 463 
 464         CHECK_READ_ONLY(req);
 465 
 466         if (ren->generic.level != RAW_RENAME_RENAME) {
 467                 return NT_STATUS_INVALID_LEVEL;
 468         }
 469 
 470         unix_path1 = svfs_unix_path(ntvfs, req, ren->rename.in.pattern1);
 471         unix_path2 = svfs_unix_path(ntvfs, req, ren->rename.in.pattern2);
 472 
 473         if (rename(unix_path1, unix_path2) == -1) {
 474                 return map_nt_error_from_unix(errno);
 475         }
 476         
 477         return NT_STATUS_OK;
 478 }
 479 
 480 /*
 481   copy a set of files
 482 */
 483 static NTSTATUS svfs_copy(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 484                           struct ntvfs_request *req, struct smb_copy *cp)
 485 {
 486         return NT_STATUS_NOT_SUPPORTED;
 487 }
 488 
 489 /*
 490   read from a file
 491 */
 492 static NTSTATUS svfs_read(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 493                           struct ntvfs_request *req, union smb_read *rd)
 494 {
 495         struct svfs_private *p = ntvfs->private_data;
 496         struct svfs_file *f;
 497         ssize_t ret;
 498 
 499         if (rd->generic.level != RAW_READ_READX) {
 500                 return NT_STATUS_NOT_SUPPORTED;
 501         }
 502 
 503         f = find_fd(p, rd->readx.in.file.ntvfs);
 504         if (!f) {
 505                 return NT_STATUS_INVALID_HANDLE;
 506         }
 507 
 508         ret = pread(f->fd, 
 509                     rd->readx.out.data, 
 510                     rd->readx.in.maxcnt,
 511                     rd->readx.in.offset);
 512         if (ret == -1) {
 513                 return map_nt_error_from_unix(errno);
 514         }
 515 
 516         rd->readx.out.nread = ret;
 517         rd->readx.out.remaining = 0; /* should fill this in? */
 518         rd->readx.out.compaction_mode = 0; 
 519 
 520         return NT_STATUS_OK;
 521 }
 522 
 523 /*
 524   write to a file
 525 */
 526 static NTSTATUS svfs_write(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 527                            struct ntvfs_request *req, union smb_write *wr)
 528 {
 529         struct svfs_private *p = ntvfs->private_data;
 530         struct svfs_file *f;
 531         ssize_t ret;
 532 
 533         if (wr->generic.level != RAW_WRITE_WRITEX) {
 534                 return ntvfs_map_write(ntvfs, req, wr);
 535         }
 536 
 537         CHECK_READ_ONLY(req);
 538 
 539         f = find_fd(p, wr->writex.in.file.ntvfs);
 540         if (!f) {
 541                 return NT_STATUS_INVALID_HANDLE;
 542         }
 543 
 544         ret = pwrite(f->fd, 
 545                      wr->writex.in.data, 
 546                      wr->writex.in.count,
 547                      wr->writex.in.offset);
 548         if (ret == -1) {
 549                 return map_nt_error_from_unix(errno);
 550         }
 551                 
 552         wr->writex.out.nwritten = ret;
 553         wr->writex.out.remaining = 0; /* should fill this in? */
 554         
 555         return NT_STATUS_OK;
 556 }
 557 
 558 /*
 559   seek in a file
 560 */
 561 static NTSTATUS svfs_seek(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 562                           struct ntvfs_request *req,
 563                           union smb_seek *io)
 564 {
 565         return NT_STATUS_NOT_SUPPORTED;
 566 }
 567 
 568 /*
 569   flush a file
 570 */
 571 static NTSTATUS svfs_flush(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 572                            struct ntvfs_request *req,
 573                            union smb_flush *io)
 574 {
 575         struct svfs_private *p = ntvfs->private_data;
 576         struct svfs_file *f;
 577 
 578         switch (io->generic.level) {
 579         case RAW_FLUSH_FLUSH:
 580         case RAW_FLUSH_SMB2:
 581                 /* ignore the additional unknown option in SMB2 */
 582                 f = find_fd(p, io->generic.in.file.ntvfs);
 583                 if (!f) {
 584                         return NT_STATUS_INVALID_HANDLE;
 585                 }
 586                 fsync(f->fd);
 587                 return NT_STATUS_OK;
 588 
 589         case RAW_FLUSH_ALL:
 590                 for (f=p->open_files;f;f=f->next) {
 591                         fsync(f->fd);
 592                 }
 593                 return NT_STATUS_OK;
 594         }
 595 
 596         return NT_STATUS_INVALID_LEVEL;
 597 }
 598 
 599 /*
 600   close a file
 601 */
 602 static NTSTATUS svfs_close(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 603                            struct ntvfs_request *req,
 604                            union smb_close *io)
 605 {
 606         struct svfs_private *p = ntvfs->private_data;
 607         struct svfs_file *f;
 608 
 609         if (io->generic.level != RAW_CLOSE_CLOSE) {
 610                 /* we need a mapping function */
 611                 return NT_STATUS_INVALID_LEVEL;
 612         }
 613 
 614         f = find_fd(p, io->close.in.file.ntvfs);
 615         if (!f) {
 616                 return NT_STATUS_INVALID_HANDLE;
 617         }
 618 
 619         if (close(f->fd) == -1) {
 620                 return map_nt_error_from_unix(errno);
 621         }
 622 
 623         DLIST_REMOVE(p->open_files, f);
 624         talloc_free(f->name);
 625         talloc_free(f);
 626 
 627         return NT_STATUS_OK;
 628 }
 629 
 630 /*
 631   exit - closing files
 632 */
 633 static NTSTATUS svfs_exit(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 634                           struct ntvfs_request *req)
 635 {
 636         return NT_STATUS_NOT_SUPPORTED;
 637 }
 638 
 639 /*
 640   logoff - closing files
 641 */
 642 static NTSTATUS svfs_logoff(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 643                             struct ntvfs_request *req)
 644 {
 645         return NT_STATUS_NOT_SUPPORTED;
 646 }
 647 
 648 /*
 649   setup for an async call
 650 */
 651 static NTSTATUS svfs_async_setup(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 652                                  struct ntvfs_request *req, 
 653                                  void *private_data)
 654 {
 655         return NT_STATUS_OK;
 656 }
 657 
 658 /*
 659   cancel an async call
 660 */
 661 static NTSTATUS svfs_cancel(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 662 {
 663         return NT_STATUS_UNSUCCESSFUL;
 664 }
 665 
 666 /*
 667   lock a byte range
 668 */
 669 static NTSTATUS svfs_lock(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 670                           struct ntvfs_request *req, union smb_lock *lck)
 671 {
 672         DEBUG(0,("REWRITE: not doing byte range locking!\n"));
 673         return NT_STATUS_OK;
 674 }
 675 
 676 /*
 677   set info on a pathname
 678 */
 679 static NTSTATUS svfs_setpathinfo(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 680                                  struct ntvfs_request *req, union smb_setfileinfo *st)
 681 {
 682         CHECK_READ_ONLY(req);
 683 
 684         return NT_STATUS_NOT_SUPPORTED;
 685 }
 686 
 687 /*
 688   set info on a open file
 689 */
 690 static NTSTATUS svfs_setfileinfo(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 691                                  struct ntvfs_request *req, 
 692                                  union smb_setfileinfo *info)
 693 {
 694         struct svfs_private *p = ntvfs->private_data;
 695         struct svfs_file *f;
 696         struct utimbuf unix_times;
 697 
 698         CHECK_READ_ONLY(req);
 699 
 700         f = find_fd(p, info->generic.in.file.ntvfs);
 701         if (!f) {
 702                 return NT_STATUS_INVALID_HANDLE;
 703         }
 704         
 705         switch (info->generic.level) {
 706         case RAW_SFILEINFO_END_OF_FILE_INFO:
 707         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
 708                 if (ftruncate(f->fd, 
 709                               info->end_of_file_info.in.size) == -1) {
 710                         return map_nt_error_from_unix(errno);
 711                 }
 712                 break;
 713         case RAW_SFILEINFO_SETATTRE:
 714                 unix_times.actime = info->setattre.in.access_time;
 715                 unix_times.modtime = info->setattre.in.write_time;
 716 
 717                 if (unix_times.actime == 0 && unix_times.modtime == 0) {
 718                         break;
 719                 } 
 720 
 721                 /* set modify time = to access time if modify time was 0 */
 722                 if (unix_times.actime != 0 && unix_times.modtime == 0) {
 723                         unix_times.modtime = unix_times.actime;
 724                 }
 725 
 726                 /* Set the date on this file */
 727                 if (svfs_file_utime(f->fd, &unix_times) != 0) {
 728                         return NT_STATUS_ACCESS_DENIED;
 729                 }
 730                 break;
 731         default:
 732                 DEBUG(2,("svfs_setfileinfo: level %d not implemented\n", 
 733                          info->generic.level));
 734                 return NT_STATUS_NOT_IMPLEMENTED;
 735         }
 736         return NT_STATUS_OK;
 737 }
 738 
 739 
 740 /*
 741   return filesystem space info
 742 */
 743 static NTSTATUS svfs_fsinfo(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 744                             struct ntvfs_request *req, union smb_fsinfo *fs)
 745 {
 746         struct svfs_private *p = ntvfs->private_data;
 747         struct stat st;
 748 
 749         if (fs->generic.level != RAW_QFS_GENERIC) {
 750                 return ntvfs_map_fsinfo(ntvfs, req, fs);
 751         }
 752 
 753         if (sys_fsusage(p->connectpath,
 754                         &fs->generic.out.blocks_free, 
 755                         &fs->generic.out.blocks_total) == -1) {
 756                 return map_nt_error_from_unix(errno);
 757         }
 758 
 759         fs->generic.out.block_size = 512;
 760 
 761         if (stat(p->connectpath, &st) != 0) {
 762                 return NT_STATUS_DISK_CORRUPT_ERROR;
 763         }
 764         
 765         fs->generic.out.fs_id = st.st_ino;
 766         unix_to_nt_time(&fs->generic.out.create_time, st.st_ctime);
 767         fs->generic.out.serial_number = st.st_ino;
 768         fs->generic.out.fs_attr = 0;
 769         fs->generic.out.max_file_component_length = 255;
 770         fs->generic.out.device_type = 0;
 771         fs->generic.out.device_characteristics = 0;
 772         fs->generic.out.quota_soft = 0;
 773         fs->generic.out.quota_hard = 0;
 774         fs->generic.out.quota_flags = 0;
 775         fs->generic.out.volume_name = talloc_strdup(req, ntvfs->ctx->config->name);
 776         fs->generic.out.fs_type = ntvfs->ctx->fs_type;
 777 
 778         return NT_STATUS_OK;
 779 }
 780 
 781 #if 0
 782 /*
 783   return filesystem attribute info
 784 */
 785 static NTSTATUS svfs_fsattr(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 786                             struct ntvfs_request *req, union smb_fsattr *fs)
 787 {
 788         struct stat st;
 789         struct svfs_private *p = ntvfs->private_data;
 790 
 791         if (fs->generic.level != RAW_FSATTR_GENERIC) {
 792                 return ntvfs_map_fsattr(ntvfs, req, fs);
 793         }
 794 
 795         if (stat(p->connectpath, &st) == -1) {
 796                 return map_nt_error_from_unix(errno);
 797         }
 798 
 799         unix_to_nt_time(&fs->generic.out.create_time, st.st_ctime);
 800         fs->generic.out.fs_attr = 
 801                 FILE_CASE_PRESERVED_NAMES | 
 802                 FILE_CASE_SENSITIVE_SEARCH | 
 803                 FILE_PERSISTENT_ACLS;
 804         fs->generic.out.max_file_component_length = 255;
 805         fs->generic.out.serial_number = 1;
 806         fs->generic.out.fs_type = talloc_strdup(req, "NTFS");
 807         fs->generic.out.volume_name = talloc_strdup(req, 
 808                                                     lp_servicename(req->tcon->service));
 809 
 810         return NT_STATUS_OK;
 811 }
 812 #endif
 813 
 814 /*
 815   return print queue info
 816 */
 817 static NTSTATUS svfs_lpq(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 818                          struct ntvfs_request *req, union smb_lpq *lpq)
 819 {
 820         return NT_STATUS_NOT_SUPPORTED;
 821 }
 822 
 823 /* 
 824    list files in a directory matching a wildcard pattern
 825 */
 826 static NTSTATUS svfs_search_first(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 827                                   struct ntvfs_request *req, union smb_search_first *io, 
 828                                   void *search_private, 
 829                                   bool (*callback)(void *, const union smb_search_data *))
 830 {
 831         struct svfs_dir *dir;
 832         int i;
 833         struct svfs_private *p = ntvfs->private_data;
 834         struct search_state *search;
 835         union smb_search_data file;
 836         uint_t max_count;
 837 
 838         if (io->generic.level != RAW_SEARCH_TRANS2) {
 839                 return NT_STATUS_NOT_SUPPORTED;
 840         }
 841 
 842         if (io->generic.data_level != RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO) {
 843                 return NT_STATUS_NOT_SUPPORTED;
 844         }
 845 
 846         search = talloc_zero(p, struct search_state);
 847         if (!search) {
 848                 return NT_STATUS_NO_MEMORY;
 849         }
 850 
 851         max_count = io->t2ffirst.in.max_count;
 852 
 853         dir = svfs_list(ntvfs, req, io->t2ffirst.in.pattern);
 854         if (!dir) {
 855                 return NT_STATUS_FOOBAR;
 856         }
 857 
 858         search->handle = p->next_search_handle;
 859         search->dir = dir;
 860 
 861         if (dir->count < max_count) {
 862                 max_count = dir->count;
 863         }
 864 
 865         for (i=0; i < max_count;i++) {
 866                 ZERO_STRUCT(file);
 867                 unix_to_nt_time(&file.both_directory_info.create_time, dir->files[i].st.st_ctime);
 868                 unix_to_nt_time(&file.both_directory_info.access_time, dir->files[i].st.st_atime);
 869                 unix_to_nt_time(&file.both_directory_info.write_time,  dir->files[i].st.st_mtime);
 870                 unix_to_nt_time(&file.both_directory_info.change_time, dir->files[i].st.st_mtime);
 871                 file.both_directory_info.name.s = dir->files[i].name;
 872                 file.both_directory_info.short_name.s = dir->files[i].name;
 873                 file.both_directory_info.size = dir->files[i].st.st_size;
 874                 file.both_directory_info.attrib = svfs_unix_to_dos_attrib(dir->files[i].st.st_mode);
 875 
 876                 if (!callback(search_private, &file)) {
 877                         break;
 878                 }
 879         }
 880 
 881         search->current_index = i;
 882 
 883         io->t2ffirst.out.count = i;
 884         io->t2ffirst.out.handle = search->handle;
 885         io->t2ffirst.out.end_of_search = (i == dir->count) ? 1 : 0;
 886 
 887         /* work out if we are going to keep the search state */
 888         if ((io->t2ffirst.in.flags & FLAG_TRANS2_FIND_CLOSE) ||
 889             ((io->t2ffirst.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && (i == dir->count))) {
 890                 talloc_free(search);
 891         } else {
 892                 p->next_search_handle++;
 893                 DLIST_ADD(p->search, search);
 894         }
 895 
 896         return NT_STATUS_OK;
 897 }
 898 
 899 /* continue a search */
 900 static NTSTATUS svfs_search_next(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 901                                  struct ntvfs_request *req, union smb_search_next *io, 
 902                                  void *search_private, 
 903                                  bool (*callback)(void *, const union smb_search_data *))
 904 {
 905         struct svfs_dir *dir;
 906         int i;
 907         struct svfs_private *p = ntvfs->private_data;
 908         struct search_state *search;
 909         union smb_search_data file;
 910         uint_t max_count;
 911 
 912         if (io->generic.level != RAW_SEARCH_TRANS2) {
 913                 return NT_STATUS_NOT_SUPPORTED;
 914         }
 915 
 916         if (io->generic.data_level != RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO) {
 917                 return NT_STATUS_NOT_SUPPORTED;
 918         }
 919 
 920         for (search=p->search; search; search = search->next) {
 921                 if (search->handle == io->t2fnext.in.handle) break;
 922         }
 923         
 924         if (!search) {
 925                 /* we didn't find the search handle */
 926                 return NT_STATUS_FOOBAR;
 927         }
 928 
 929         dir = search->dir;
 930 
 931         /* the client might be asking for something other than just continuing
 932            with the search */
 933         if (!(io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE) &&
 934             (io->t2fnext.in.flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) &&
 935             io->t2fnext.in.last_name && *io->t2fnext.in.last_name) {
 936                 /* look backwards first */
 937                 for (i=search->current_index; i > 0; i--) {
 938                         if (strcmp(io->t2fnext.in.last_name, dir->files[i-1].name) == 0) {
 939                                 search->current_index = i;
 940                                 goto found;
 941                         }
 942                 }
 943 
 944                 /* then look forwards */
 945                 for (i=search->current_index+1; i <= dir->count; i++) {
 946                         if (strcmp(io->t2fnext.in.last_name, dir->files[i-1].name) == 0) {
 947                                 search->current_index = i;
 948                                 goto found;
 949                         }
 950                 }
 951         }
 952 
 953 found:  
 954         max_count = search->current_index + io->t2fnext.in.max_count;
 955 
 956         if (max_count > dir->count) {
 957                 max_count = dir->count;
 958         }
 959 
 960         for (i = search->current_index; i < max_count;i++) {
 961                 ZERO_STRUCT(file);
 962                 unix_to_nt_time(&file.both_directory_info.create_time, dir->files[i].st.st_ctime);
 963                 unix_to_nt_time(&file.both_directory_info.access_time, dir->files[i].st.st_atime);
 964                 unix_to_nt_time(&file.both_directory_info.write_time,  dir->files[i].st.st_mtime);
 965                 unix_to_nt_time(&file.both_directory_info.change_time, dir->files[i].st.st_mtime);
 966                 file.both_directory_info.name.s = dir->files[i].name;
 967                 file.both_directory_info.short_name.s = dir->files[i].name;
 968                 file.both_directory_info.size = dir->files[i].st.st_size;
 969                 file.both_directory_info.attrib = svfs_unix_to_dos_attrib(dir->files[i].st.st_mode);
 970 
 971                 if (!callback(search_private, &file)) {
 972                         break;
 973                 }
 974         }
 975 
 976         io->t2fnext.out.count = i - search->current_index;
 977         io->t2fnext.out.end_of_search = (i == dir->count) ? 1 : 0;
 978 
 979         search->current_index = i;
 980 
 981         /* work out if we are going to keep the search state */
 982         if ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE) ||
 983             ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && (i == dir->count))) {
 984                 DLIST_REMOVE(p->search, search);
 985                 talloc_free(search);
 986         }
 987 
 988         return NT_STATUS_OK;
 989 }
 990 
 991 /* close a search */
 992 static NTSTATUS svfs_search_close(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 993                                   struct ntvfs_request *req, union smb_search_close *io)
 994 {
 995         struct svfs_private *p = ntvfs->private_data;
 996         struct search_state *search;
 997 
 998         for (search=p->search; search; search = search->next) {
 999                 if (search->handle == io->findclose.in.handle) break;
1000         }
1001         
1002         if (!search) {
1003                 /* we didn't find the search handle */
1004                 return NT_STATUS_FOOBAR;
1005         }
1006 
1007         DLIST_REMOVE(p->search, search);
1008         talloc_free(search);
1009 
1010         return NT_STATUS_OK;
1011 }
1012 
1013 /* SMBtrans - not used on file shares */
1014 static NTSTATUS svfs_trans(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
1015                            struct ntvfs_request *req, struct smb_trans2 *trans2)
1016 {
1017         return NT_STATUS_ACCESS_DENIED;
1018 }
1019 
1020 
1021 /*
1022   initialialise the POSIX disk backend, registering ourselves with the ntvfs subsystem
1023  */
1024 NTSTATUS ntvfs_simple_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
1025 {
1026         NTSTATUS ret;
1027         struct ntvfs_ops ops;
1028         NTVFS_CURRENT_CRITICAL_SIZES(vers);
1029 
1030         ZERO_STRUCT(ops);
1031 
1032         /* fill in all the operations */
1033         ops.connect = svfs_connect;
1034         ops.disconnect = svfs_disconnect;
1035         ops.unlink = svfs_unlink;
1036         ops.chkpath = svfs_chkpath;
1037         ops.qpathinfo = svfs_qpathinfo;
1038         ops.setpathinfo = svfs_setpathinfo;
1039         ops.open = svfs_open;
1040         ops.mkdir = svfs_mkdir;
1041         ops.rmdir = svfs_rmdir;
1042         ops.rename = svfs_rename;
1043         ops.copy = svfs_copy;
1044         ops.ioctl = svfs_ioctl;
1045         ops.read = svfs_read;
1046         ops.write = svfs_write;
1047         ops.seek = svfs_seek;
1048         ops.flush = svfs_flush; 
1049         ops.close = svfs_close;
1050         ops.exit = svfs_exit;
1051         ops.lock = svfs_lock;
1052         ops.setfileinfo = svfs_setfileinfo;
1053         ops.qfileinfo = svfs_qfileinfo;
1054         ops.fsinfo = svfs_fsinfo;
1055         ops.lpq = svfs_lpq;
1056         ops.search_first = svfs_search_first;
1057         ops.search_next = svfs_search_next;
1058         ops.search_close = svfs_search_close;
1059         ops.trans = svfs_trans;
1060         ops.logoff = svfs_logoff;
1061         ops.async_setup = svfs_async_setup;
1062         ops.cancel = svfs_cancel;
1063 
1064         /* register ourselves with the NTVFS subsystem. We register
1065            under names 'simple'
1066         */
1067 
1068         ops.type = NTVFS_DISK;
1069         ops.name = "simple";
1070         ret = ntvfs_register(&ops, &vers);
1071 
1072         if (!NT_STATUS_IS_OK(ret)) {
1073                 DEBUG(0,("Failed to register simple backend with name: %s!\n",
1074                          ops.name));
1075         }
1076 
1077         return ret;
1078 }

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