root/source4/ntvfs/posix/pvfs_open.c

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

DEFINITIONS

This source file includes following definitions.
  1. pvfs_find_fd
  2. pvfs_dir_handle_destructor
  3. pvfs_dir_fnum_destructor
  4. pvfs_open_setup_eas_acl
  5. pvfs_locking_key
  6. pvfs_open_directory
  7. pvfs_handle_destructor
  8. pvfs_fnum_destructor
  9. pvfs_brl_locking_handle
  10. pvfs_create_file
  11. pvfs_odb_retry_destructor
  12. pvfs_odb_retry_callback
  13. pvfs_odb_retry_setup
  14. pvfs_retry_open_sharing
  15. pvfs_open_deny_dos
  16. pvfs_open_setup_retry
  17. pvfs_open
  18. pvfs_close
  19. pvfs_logoff
  20. pvfs_exit
  21. pvfs_set_delete_on_close
  22. pvfs_can_delete
  23. pvfs_can_rename
  24. pvfs_can_update_file_size
  25. pvfs_can_stat
  26. pvfs_delete_on_close_set

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    POSIX NTVFS backend - open and close
   5 
   6    Copyright (C) Andrew Tridgell 2004
   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 "vfs_posix.h"
  24 #include "system/dir.h"
  25 #include "system/time.h"
  26 #include "../lib/util/dlinklist.h"
  27 #include "messaging/messaging.h"
  28 #include "librpc/gen_ndr/xattr.h"
  29 
  30 /*
  31   find open file handle given fnum
  32 */
  33 struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
     /* [<][>][^][v][top][bottom][index][help] */
  34                                struct ntvfs_request *req, struct ntvfs_handle *h)
  35 {
  36         void *p;
  37         struct pvfs_file *f;
  38 
  39         p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
  40         if (!p) return NULL;
  41 
  42         f = talloc_get_type(p, struct pvfs_file);
  43         if (!f) return NULL;
  44 
  45         return f;
  46 }
  47 
  48 /*
  49   cleanup a open directory handle
  50 */
  51 static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
     /* [<][>][^][v][top][bottom][index][help] */
  52 {
  53         if (h->have_opendb_entry) {
  54                 struct odb_lock *lck;
  55                 NTSTATUS status;
  56                 const char *delete_path = NULL;
  57 
  58                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
  59                 if (lck == NULL) {
  60                         DEBUG(0,("Unable to lock opendb for close\n"));
  61                         return 0;
  62                 }
  63 
  64                 status = odb_close_file(lck, h, &delete_path);
  65                 if (!NT_STATUS_IS_OK(status)) {
  66                         DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
  67                                  h->name->full_name, nt_errstr(status)));
  68                 }
  69 
  70                 if (h->name->stream_name == NULL && delete_path) {
  71                         status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
  72                         if (!NT_STATUS_IS_OK(status)) {
  73                                 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
  74                                          delete_path, nt_errstr(status)));
  75                         }
  76                         if (rmdir(delete_path) != 0) {
  77                                 DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
  78                                          delete_path, strerror(errno)));
  79                         }
  80                 }
  81 
  82                 talloc_free(lck);
  83         }
  84 
  85         return 0;
  86 }
  87 
  88 /*
  89   cleanup a open directory fnum
  90 */
  91 static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
     /* [<][>][^][v][top][bottom][index][help] */
  92 {
  93         DLIST_REMOVE(f->pvfs->files.list, f);
  94         ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
  95 
  96         return 0;
  97 }
  98 
  99 /*
 100   setup any EAs and the ACL on newly created files/directories
 101 */
 102 static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 103                                         struct ntvfs_request *req,
 104                                         struct pvfs_filename *name,
 105                                         int fd, struct pvfs_file *f,
 106                                         union smb_open *io)
 107 {
 108         NTSTATUS status;
 109         struct security_descriptor *sd;
 110 
 111         /* setup any EAs that were asked for */
 112         if (io->ntcreatex.in.ea_list) {
 113                 status = pvfs_setfileinfo_ea_set(pvfs, name, fd, 
 114                                                  io->ntcreatex.in.ea_list->num_eas,
 115                                                  io->ntcreatex.in.ea_list->eas);
 116                 if (!NT_STATUS_IS_OK(status)) {
 117                         return status;
 118                 }
 119         }
 120 
 121         sd = io->ntcreatex.in.sec_desc;
 122         /* setup an initial sec_desc if requested */
 123         if (sd && (sd->type & SEC_DESC_DACL_PRESENT)) {
 124                 union smb_setfileinfo set;
 125 /* 
 126  * TODO: set the full ACL! 
 127  *       - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
 128  *         when a SACL is present on the sd,
 129  *         but the user doesn't have SeSecurityPrivilege
 130  *       - w2k3 allows it
 131  */
 132                 set.set_secdesc.in.file.ntvfs = f->ntvfs;
 133                 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
 134                 set.set_secdesc.in.sd = sd;
 135 
 136                 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
 137         } else {
 138                 /* otherwise setup an inherited acl from the parent */
 139                 status = pvfs_acl_inherit(pvfs, req, name, fd);
 140         }
 141 
 142         return status;
 143 }
 144 
 145 /*
 146   form the lock context used for opendb locking. Note that we must
 147   zero here to take account of possible padding on some architectures
 148 */
 149 NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
     /* [<][>][^][v][top][bottom][index][help] */
 150                           TALLOC_CTX *mem_ctx, DATA_BLOB *key)
 151 {
 152         struct {
 153                 dev_t device;
 154                 ino_t inode;
 155         } lock_context;
 156         ZERO_STRUCT(lock_context);
 157 
 158         lock_context.device = name->st.st_dev;
 159         lock_context.inode = name->st.st_ino;
 160 
 161         *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
 162         if (key->data == NULL) {
 163                 return NT_STATUS_NO_MEMORY;
 164         }
 165         
 166         return NT_STATUS_OK;
 167 }
 168 
 169 
 170 /*
 171   open a directory
 172 */
 173 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 174                                     struct ntvfs_request *req, 
 175                                     struct pvfs_filename *name, 
 176                                     union smb_open *io)
 177 {
 178         struct pvfs_file *f;
 179         struct ntvfs_handle *h;
 180         NTSTATUS status;
 181         uint32_t create_action;
 182         uint32_t access_mask = io->generic.in.access_mask;
 183         struct odb_lock *lck;
 184         bool del_on_close;
 185         uint32_t create_options;
 186         uint32_t share_access;
 187         bool forced;
 188 
 189         create_options = io->generic.in.create_options;
 190         share_access   = io->generic.in.share_access;
 191 
 192         forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
 193 
 194         if (name->stream_name) {
 195                 if (forced) {
 196                         return NT_STATUS_NOT_A_DIRECTORY;
 197                 } else {
 198                         return NT_STATUS_FILE_IS_A_DIRECTORY;
 199                 }
 200         }
 201 
 202         /* if the client says it must be a directory, and it isn't,
 203            then fail */
 204         if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
 205                 return NT_STATUS_NOT_A_DIRECTORY;
 206         }
 207 
 208         /* found with gentest */
 209         if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
 210             (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
 211             (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
 212                 return NT_STATUS_INVALID_PARAMETER;
 213         }
 214         
 215         switch (io->generic.in.open_disposition) {
 216         case NTCREATEX_DISP_OPEN_IF:
 217                 break;
 218 
 219         case NTCREATEX_DISP_OPEN:
 220                 if (!name->exists) {
 221                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 222                 }
 223                 break;
 224 
 225         case NTCREATEX_DISP_CREATE:
 226                 if (name->exists) {
 227                         return NT_STATUS_OBJECT_NAME_COLLISION;
 228                 }
 229                 break;
 230 
 231         case NTCREATEX_DISP_OVERWRITE_IF:
 232         case NTCREATEX_DISP_OVERWRITE:
 233         case NTCREATEX_DISP_SUPERSEDE:
 234         default:
 235                 return NT_STATUS_INVALID_PARAMETER;
 236         }
 237 
 238         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
 239         NT_STATUS_NOT_OK_RETURN(status);
 240 
 241         f = talloc(h, struct pvfs_file);
 242         if (f == NULL) {
 243                 return NT_STATUS_NO_MEMORY;
 244         }
 245 
 246         f->handle = talloc(f, struct pvfs_file_handle);
 247         if (f->handle == NULL) {
 248                 return NT_STATUS_NO_MEMORY;
 249         }
 250 
 251         if (name->exists) {
 252                 /* check the security descriptor */
 253                 status = pvfs_access_check(pvfs, req, name, &access_mask);
 254         } else {
 255                 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
 256         }
 257         NT_STATUS_NOT_OK_RETURN(status);
 258 
 259         if (io->generic.in.query_maximal_access) {
 260                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
 261                                                      &io->generic.out.maximal_access);
 262                 NT_STATUS_NOT_OK_RETURN(status);
 263         }
 264 
 265         f->ntvfs         = h;
 266         f->pvfs          = pvfs;
 267         f->pending_list  = NULL;
 268         f->lock_count    = 0;
 269         f->share_access  = io->generic.in.share_access;
 270         f->impersonation = io->generic.in.impersonation;
 271         f->access_mask   = access_mask;
 272         f->brl_handle    = NULL;
 273         f->notify_buffer = NULL;
 274         f->search        = NULL;
 275 
 276         f->handle->pvfs              = pvfs;
 277         f->handle->name              = talloc_steal(f->handle, name);
 278         f->handle->fd                = -1;
 279         f->handle->odb_locking_key   = data_blob(NULL, 0);
 280         f->handle->create_options    = io->generic.in.create_options;
 281         f->handle->seek_offset       = 0;
 282         f->handle->position          = 0;
 283         f->handle->mode              = 0;
 284         f->handle->oplock            = NULL;
 285         ZERO_STRUCT(f->handle->write_time);
 286         f->handle->open_completed    = false;
 287 
 288         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
 289             pvfs_directory_empty(pvfs, f->handle->name)) {
 290                 del_on_close = true;
 291         } else {
 292                 del_on_close = false;
 293         }
 294 
 295         if (name->exists) {
 296                 /* form the lock context used for opendb locking */
 297                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
 298                 if (!NT_STATUS_IS_OK(status)) {
 299                         return status;
 300                 }
 301 
 302                 /* get a lock on this file before the actual open */
 303                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
 304                 if (lck == NULL) {
 305                         DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
 306                                  name->full_name));
 307                         /* we were supposed to do a blocking lock, so something
 308                            is badly wrong! */
 309                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
 310                 }
 311                 
 312                 /* see if we are allowed to open at the same time as existing opens */
 313                 status = odb_can_open(lck, name->stream_id,
 314                                       share_access, access_mask, del_on_close,
 315                                       io->generic.in.open_disposition, false);
 316                 if (!NT_STATUS_IS_OK(status)) {
 317                         talloc_free(lck);
 318                         return status;
 319                 }
 320 
 321                 /* now really mark the file as open */
 322                 status = odb_open_file(lck, f->handle, name->full_name,
 323                                        NULL, name->dos.write_time,
 324                                        false, OPLOCK_NONE, NULL);
 325 
 326                 if (!NT_STATUS_IS_OK(status)) {
 327                         talloc_free(lck);
 328                         return status;
 329                 }
 330 
 331                 f->handle->have_opendb_entry = true;
 332         }
 333 
 334         DLIST_ADD(pvfs->files.list, f);
 335 
 336         /* setup destructors to avoid leaks on abnormal termination */
 337         talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
 338         talloc_set_destructor(f, pvfs_dir_fnum_destructor);
 339 
 340         if (!name->exists) {
 341                 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
 342                 mode_t mode = pvfs_fileperms(pvfs, attrib);
 343 
 344                 if (mkdir(name->full_name, mode) == -1) {
 345                         return pvfs_map_errno(pvfs,errno);
 346                 }
 347 
 348                 pvfs_xattr_unlink_hook(pvfs, name->full_name);
 349 
 350                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
 351                 if (!NT_STATUS_IS_OK(status)) {
 352                         goto cleanup_delete;
 353                 }
 354 
 355                 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
 356                 if (!NT_STATUS_IS_OK(status)) {
 357                         goto cleanup_delete;
 358                 }
 359 
 360                 /* form the lock context used for opendb locking */
 361                 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
 362                 if (!NT_STATUS_IS_OK(status)) {
 363                         return status;
 364                 }
 365 
 366                 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
 367                 if (lck == NULL) {
 368                         DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
 369                                  name->full_name));
 370                         /* we were supposed to do a blocking lock, so something
 371                            is badly wrong! */
 372                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
 373                 }
 374 
 375                 status = odb_can_open(lck, name->stream_id,
 376                                       share_access, access_mask, del_on_close,
 377                                       io->generic.in.open_disposition, false);
 378 
 379                 if (!NT_STATUS_IS_OK(status)) {
 380                         goto cleanup_delete;
 381                 }
 382 
 383                 status = odb_open_file(lck, f->handle, name->full_name,
 384                                        NULL, name->dos.write_time,
 385                                        false, OPLOCK_NONE, NULL);
 386 
 387                 if (!NT_STATUS_IS_OK(status)) {
 388                         goto cleanup_delete;
 389                 }
 390 
 391                 f->handle->have_opendb_entry = true;
 392 
 393                 create_action = NTCREATEX_ACTION_CREATED;
 394 
 395                 notify_trigger(pvfs->notify_context, 
 396                                NOTIFY_ACTION_ADDED, 
 397                                FILE_NOTIFY_CHANGE_DIR_NAME,
 398                                name->full_name);
 399         } else {
 400                 create_action = NTCREATEX_ACTION_EXISTED;
 401         }
 402 
 403         if (!name->exists) {
 404                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 405         }
 406 
 407         /* the open succeeded, keep this handle permanently */
 408         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
 409         if (!NT_STATUS_IS_OK(status)) {
 410                 goto cleanup_delete;
 411         }
 412 
 413         f->handle->open_completed = true;
 414 
 415         io->generic.out.oplock_level  = OPLOCK_NONE;
 416         io->generic.out.file.ntvfs    = h;
 417         io->generic.out.create_action = create_action;
 418         io->generic.out.create_time   = name->dos.create_time;
 419         io->generic.out.access_time   = name->dos.access_time;
 420         io->generic.out.write_time    = name->dos.write_time;
 421         io->generic.out.change_time   = name->dos.change_time;
 422         io->generic.out.attrib        = name->dos.attrib;
 423         io->generic.out.alloc_size    = name->dos.alloc_size;
 424         io->generic.out.size          = name->st.st_size;
 425         io->generic.out.file_type     = FILE_TYPE_DISK;
 426         io->generic.out.ipc_state     = 0;
 427         io->generic.out.is_directory  = 1;
 428 
 429         return NT_STATUS_OK;
 430 
 431 cleanup_delete:
 432         rmdir(name->full_name);
 433         return status;
 434 }
 435 
 436 /*
 437   destroy a struct pvfs_file_handle
 438 */
 439 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
     /* [<][>][^][v][top][bottom][index][help] */
 440 {
 441         talloc_free(h->write_time.update_event);
 442         h->write_time.update_event = NULL;
 443 
 444         if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
 445             h->name->stream_name) {
 446                 NTSTATUS status;
 447                 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
 448                 if (!NT_STATUS_IS_OK(status)) {
 449                         DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
 450                                  h->name->stream_name, h->name->full_name));
 451                 }
 452         }
 453 
 454         if (h->fd != -1) {
 455                 if (close(h->fd) != 0) {
 456                         DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
 457                                  h->fd, h->name->full_name, strerror(errno)));
 458                 }
 459                 h->fd = -1;
 460         }
 461 
 462         if (!h->write_time.update_forced &&
 463             h->write_time.update_on_close &&
 464             h->write_time.close_time == 0) {
 465                 struct timeval tv;
 466                 tv = timeval_current();
 467                 h->write_time.close_time = timeval_to_nttime(&tv);
 468         }
 469 
 470         if (h->have_opendb_entry) {
 471                 struct odb_lock *lck;
 472                 NTSTATUS status;
 473                 const char *delete_path = NULL;
 474 
 475                 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
 476                 if (lck == NULL) {
 477                         DEBUG(0,("Unable to lock opendb for close\n"));
 478                         return 0;
 479                 }
 480 
 481                 if (h->write_time.update_forced) {
 482                         status = odb_get_file_infos(h->pvfs->odb_context,
 483                                                     &h->odb_locking_key,
 484                                                     NULL,
 485                                                     &h->write_time.close_time);
 486                         if (!NT_STATUS_IS_OK(status)) {
 487                                 DEBUG(0,("Unable get write time for '%s' - %s\n",
 488                                          h->name->full_name, nt_errstr(status)));
 489                         }
 490 
 491                         h->write_time.update_forced = false;
 492                         h->write_time.update_on_close = true;
 493                 } else if (h->write_time.update_on_close) {
 494                         status = odb_set_write_time(lck, h->write_time.close_time, true);
 495                         if (!NT_STATUS_IS_OK(status)) {
 496                                 DEBUG(0,("Unable set write time for '%s' - %s\n",
 497                                          h->name->full_name, nt_errstr(status)));
 498                         }
 499                 }
 500 
 501                 status = odb_close_file(lck, h, &delete_path);
 502                 if (!NT_STATUS_IS_OK(status)) {
 503                         DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
 504                                  h->name->full_name, nt_errstr(status)));
 505                 }
 506 
 507                 if (h->name->stream_name == NULL &&
 508                     h->open_completed && delete_path) {
 509                         status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
 510                         if (!NT_STATUS_IS_OK(status)) {
 511                                 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
 512                                          delete_path, nt_errstr(status)));
 513                         }
 514                         if (unlink(delete_path) != 0) {
 515                                 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
 516                                          delete_path, strerror(errno)));
 517                         } else {
 518                                 notify_trigger(h->pvfs->notify_context,
 519                                                NOTIFY_ACTION_REMOVED,
 520                                                FILE_NOTIFY_CHANGE_FILE_NAME,
 521                                                delete_path);
 522                         }
 523                         h->write_time.update_on_close = false;
 524                 }
 525 
 526                 talloc_free(lck);
 527         }
 528 
 529         if (h->write_time.update_on_close) {
 530                 struct timeval tv[2];
 531 
 532                 nttime_to_timeval(&tv[0], h->name->dos.access_time);
 533                 nttime_to_timeval(&tv[1], h->write_time.close_time);
 534 
 535                 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
 536                         if (utimes(h->name->full_name, tv) == -1) {
 537                                 DEBUG(0,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
 538                                          h->name->full_name, strerror(errno)));
 539                         }
 540                 }
 541         }
 542 
 543         return 0;
 544 }
 545 
 546 
 547 /*
 548   destroy a struct pvfs_file
 549 */
 550 static int pvfs_fnum_destructor(struct pvfs_file *f)
     /* [<][>][^][v][top][bottom][index][help] */
 551 {
 552         DLIST_REMOVE(f->pvfs->files.list, f);
 553         pvfs_lock_close(f->pvfs, f);
 554         ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
 555 
 556         return 0;
 557 }
 558 
 559 
 560 /*
 561   form the lock context used for byte range locking. This is separate
 562   from the locking key used for opendb locking as it needs to take
 563   account of file streams (each stream is a separate byte range
 564   locking space)
 565 */
 566 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 567                                         struct pvfs_filename *name,
 568                                         struct ntvfs_handle *ntvfs,
 569                                         struct brl_handle **_h)
 570 {
 571         DATA_BLOB odb_key, key;
 572         NTSTATUS status;
 573         struct brl_handle *h;
 574 
 575         status = pvfs_locking_key(name, mem_ctx, &odb_key);
 576         NT_STATUS_NOT_OK_RETURN(status);
 577 
 578         if (name->stream_name == NULL) {
 579                 key = odb_key;
 580         } else {
 581                 key = data_blob_talloc(mem_ctx, NULL, 
 582                                        odb_key.length + strlen(name->stream_name) + 1);
 583                 NT_STATUS_HAVE_NO_MEMORY(key.data);
 584                 memcpy(key.data, odb_key.data, odb_key.length);
 585                 memcpy(key.data + odb_key.length, 
 586                        name->stream_name, strlen(name->stream_name) + 1);
 587                 data_blob_free(&odb_key);
 588         }
 589 
 590         h = brl_create_handle(mem_ctx, ntvfs, &key);
 591         NT_STATUS_HAVE_NO_MEMORY(h);
 592 
 593         *_h = h;
 594         return NT_STATUS_OK;
 595 }
 596 
 597 /*
 598   create a new file
 599 */
 600 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 601                                  struct ntvfs_request *req, 
 602                                  struct pvfs_filename *name, 
 603                                  union smb_open *io)
 604 {
 605         struct pvfs_file *f;
 606         NTSTATUS status;
 607         struct ntvfs_handle *h;
 608         int flags, fd;
 609         struct odb_lock *lck;
 610         uint32_t create_options = io->generic.in.create_options;
 611         uint32_t share_access = io->generic.in.share_access;
 612         uint32_t access_mask = io->generic.in.access_mask;
 613         mode_t mode;
 614         uint32_t attrib;
 615         bool del_on_close;
 616         struct pvfs_filename *parent;
 617         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
 618         bool allow_level_II_oplock = false;
 619 
 620         if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
 621                 return NT_STATUS_INVALID_PARAMETER;
 622         }
 623 
 624         if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
 625                 return NT_STATUS_ACCESS_DENIED;
 626         }
 627             
 628         if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
 629             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
 630                 return NT_STATUS_CANNOT_DELETE;
 631         }
 632 
 633         status = pvfs_access_check_create(pvfs, req, name, &access_mask);
 634         NT_STATUS_NOT_OK_RETURN(status);
 635 
 636         /* check that the parent isn't opened with delete on close set */
 637         status = pvfs_resolve_parent(pvfs, req, name, &parent);
 638         if (NT_STATUS_IS_OK(status)) {
 639                 DATA_BLOB locking_key;
 640                 status = pvfs_locking_key(parent, req, &locking_key);
 641                 NT_STATUS_NOT_OK_RETURN(status);
 642                 status = odb_get_file_infos(pvfs->odb_context, &locking_key,
 643                                             &del_on_close, NULL);
 644                 NT_STATUS_NOT_OK_RETURN(status);
 645                 if (del_on_close) {
 646                         return NT_STATUS_DELETE_PENDING;
 647                 }
 648         }
 649 
 650         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
 651                 flags = O_RDWR;
 652         } else {
 653                 flags = O_RDONLY;
 654         }
 655 
 656         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
 657         NT_STATUS_NOT_OK_RETURN(status);
 658 
 659         f = talloc(h, struct pvfs_file);
 660         NT_STATUS_HAVE_NO_MEMORY(f);
 661 
 662         f->handle = talloc(f, struct pvfs_file_handle);
 663         NT_STATUS_HAVE_NO_MEMORY(f->handle);
 664 
 665         attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
 666         mode = pvfs_fileperms(pvfs, attrib);
 667 
 668         /* create the file */
 669         fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
 670         if (fd == -1) {
 671                 return pvfs_map_errno(pvfs, errno);
 672         }
 673 
 674         pvfs_xattr_unlink_hook(pvfs, name->full_name);
 675 
 676         /* if this was a stream create then create the stream as well */
 677         if (name->stream_name) {
 678                 status = pvfs_stream_create(pvfs, name, fd);
 679                 if (!NT_STATUS_IS_OK(status)) {
 680                         close(fd);
 681                         return status;
 682                 }
 683         }
 684 
 685         /* re-resolve the open fd */
 686         status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
 687         if (!NT_STATUS_IS_OK(status)) {
 688                 close(fd);
 689                 return status;
 690         }
 691 
 692         /* support initial alloc sizes */
 693         name->dos.alloc_size = io->ntcreatex.in.alloc_size;
 694         name->dos.attrib = attrib;
 695         status = pvfs_dosattrib_save(pvfs, name, fd);
 696         if (!NT_STATUS_IS_OK(status)) {
 697                 goto cleanup_delete;
 698         }
 699 
 700 
 701         status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
 702         if (!NT_STATUS_IS_OK(status)) {
 703                 goto cleanup_delete;
 704         }
 705 
 706         if (io->generic.in.query_maximal_access) {
 707                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
 708                                                      &io->generic.out.maximal_access);
 709                 NT_STATUS_NOT_OK_RETURN(status);
 710         }
 711 
 712         /* form the lock context used for byte range locking and
 713            opendb locking */
 714         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
 715         if (!NT_STATUS_IS_OK(status)) {
 716                 goto cleanup_delete;
 717         }
 718 
 719         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
 720         if (!NT_STATUS_IS_OK(status)) {
 721                 goto cleanup_delete;
 722         }
 723 
 724         /* grab a lock on the open file record */
 725         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
 726         if (lck == NULL) {
 727                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
 728                          name->full_name));
 729                 /* we were supposed to do a blocking lock, so something
 730                    is badly wrong! */
 731                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 732                 goto cleanup_delete;
 733         }
 734 
 735         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
 736                 del_on_close = true;
 737         } else {
 738                 del_on_close = false;
 739         }
 740 
 741         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
 742                 oplock_level = OPLOCK_NONE;
 743         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
 744                 oplock_level = OPLOCK_BATCH;
 745         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
 746                 oplock_level = OPLOCK_EXCLUSIVE;
 747         }
 748 
 749         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
 750                 allow_level_II_oplock = true;
 751         }
 752 
 753         status = odb_can_open(lck, name->stream_id,
 754                               share_access, access_mask, del_on_close,
 755                               io->generic.in.open_disposition, false);
 756         if (!NT_STATUS_IS_OK(status)) {
 757                 talloc_free(lck);
 758                 /* bad news, we must have hit a race - we don't delete the file
 759                    here as the most likely scenario is that someone else created
 760                    the file at the same time */
 761                 close(fd);
 762                 return status;
 763         }
 764 
 765         f->ntvfs             = h;
 766         f->pvfs              = pvfs;
 767         f->pending_list      = NULL;
 768         f->lock_count        = 0;
 769         f->share_access      = io->generic.in.share_access;
 770         f->access_mask       = access_mask;
 771         f->impersonation     = io->generic.in.impersonation;
 772         f->notify_buffer     = NULL;
 773         f->search            = NULL;
 774 
 775         f->handle->pvfs              = pvfs;
 776         f->handle->name              = talloc_steal(f->handle, name);
 777         f->handle->fd                = fd;
 778         f->handle->create_options    = io->generic.in.create_options;
 779         f->handle->seek_offset       = 0;
 780         f->handle->position          = 0;
 781         f->handle->mode              = 0;
 782         f->handle->oplock            = NULL;
 783         f->handle->have_opendb_entry = true;
 784         ZERO_STRUCT(f->handle->write_time);
 785         f->handle->open_completed    = false;
 786 
 787         status = odb_open_file(lck, f->handle, name->full_name,
 788                                &f->handle->fd, name->dos.write_time,
 789                                allow_level_II_oplock,
 790                                oplock_level, &oplock_granted);
 791         talloc_free(lck);
 792         if (!NT_STATUS_IS_OK(status)) {
 793                 /* bad news, we must have hit a race - we don't delete the file
 794                    here as the most likely scenario is that someone else created
 795                    the file at the same time */
 796                 close(fd);
 797                 return status;
 798         }
 799 
 800         DLIST_ADD(pvfs->files.list, f);
 801 
 802         /* setup a destructor to avoid file descriptor leaks on
 803            abnormal termination */
 804         talloc_set_destructor(f, pvfs_fnum_destructor);
 805         talloc_set_destructor(f->handle, pvfs_handle_destructor);
 806 
 807         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
 808                 oplock_granted = OPLOCK_BATCH;
 809         } else if (oplock_granted != OPLOCK_NONE) {
 810                 status = pvfs_setup_oplock(f, oplock_granted);
 811                 if (!NT_STATUS_IS_OK(status)) {
 812                         return status;
 813                 }
 814         }
 815 
 816         io->generic.out.oplock_level  = oplock_granted;
 817         io->generic.out.file.ntvfs    = f->ntvfs;
 818         io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
 819         io->generic.out.create_time   = name->dos.create_time;
 820         io->generic.out.access_time   = name->dos.access_time;
 821         io->generic.out.write_time    = name->dos.write_time;
 822         io->generic.out.change_time   = name->dos.change_time;
 823         io->generic.out.attrib        = name->dos.attrib;
 824         io->generic.out.alloc_size    = name->dos.alloc_size;
 825         io->generic.out.size          = name->st.st_size;
 826         io->generic.out.file_type     = FILE_TYPE_DISK;
 827         io->generic.out.ipc_state     = 0;
 828         io->generic.out.is_directory  = 0;
 829 
 830         /* success - keep the file handle */
 831         status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
 832         if (!NT_STATUS_IS_OK(status)) {
 833                 goto cleanup_delete;
 834         }
 835 
 836         f->handle->open_completed = true;
 837 
 838         notify_trigger(pvfs->notify_context, 
 839                        NOTIFY_ACTION_ADDED, 
 840                        FILE_NOTIFY_CHANGE_FILE_NAME,
 841                        name->full_name);
 842 
 843         return NT_STATUS_OK;
 844 
 845 cleanup_delete:
 846         close(fd);
 847         unlink(name->full_name);
 848         return status;
 849 }
 850 
 851 /*
 852   state of a pending retry
 853 */
 854 struct pvfs_odb_retry {
 855         struct ntvfs_module_context *ntvfs;
 856         struct ntvfs_request *req;
 857         DATA_BLOB odb_locking_key;
 858         void *io;
 859         void *private_data;
 860         void (*callback)(struct pvfs_odb_retry *r,
 861                          struct ntvfs_module_context *ntvfs,
 862                          struct ntvfs_request *req,
 863                          void *io,
 864                          void *private_data,
 865                          enum pvfs_wait_notice reason);
 866 };
 867 
 868 /* destroy a pending request */
 869 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
     /* [<][>][^][v][top][bottom][index][help] */
 870 {
 871         struct pvfs_state *pvfs = talloc_get_type(r->ntvfs->private_data,
 872                                   struct pvfs_state);
 873         if (r->odb_locking_key.data) {
 874                 struct odb_lock *lck;
 875                 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
 876                 if (lck != NULL) {
 877                         odb_remove_pending(lck, r);
 878                 }
 879                 talloc_free(lck);
 880         }
 881         return 0;
 882 }
 883 
 884 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
     /* [<][>][^][v][top][bottom][index][help] */
 885 {
 886         struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
 887 
 888         if (reason == PVFS_WAIT_EVENT) {
 889                 /*
 890                  * The pending odb entry is already removed.
 891                  * We use a null locking key to indicate this
 892                  * to the destructor.
 893                  */
 894                 data_blob_free(&r->odb_locking_key);
 895         }
 896 
 897         r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
 898 }
 899 
 900 /*
 901   setup for a retry of a request that was rejected
 902   by odb_can_open()
 903 */
 904 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 905                               struct ntvfs_request *req,
 906                               struct odb_lock *lck,
 907                               struct timeval end_time,
 908                               void *io,
 909                               void *private_data,
 910                               void (*callback)(struct pvfs_odb_retry *r,
 911                                                struct ntvfs_module_context *ntvfs,
 912                                                struct ntvfs_request *req,
 913                                                void *io,
 914                                                void *private_data,
 915                                                enum pvfs_wait_notice reason))
 916 {
 917         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
 918                                   struct pvfs_state);
 919         struct pvfs_odb_retry *r;
 920         struct pvfs_wait *wait_handle;
 921         NTSTATUS status;
 922 
 923         r = talloc(req, struct pvfs_odb_retry);
 924         NT_STATUS_HAVE_NO_MEMORY(r);
 925 
 926         r->ntvfs = ntvfs;
 927         r->req = req;
 928         r->io = io;
 929         r->private_data = private_data;
 930         r->callback = callback;
 931         r->odb_locking_key = odb_get_key(r, lck);
 932         if (r->odb_locking_key.data == NULL) {
 933                 return NT_STATUS_NO_MEMORY;
 934         }
 935 
 936         /* setup a pending lock */
 937         status = odb_open_file_pending(lck, r);
 938         if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
 939                 /*
 940                  * maybe only a unix application
 941                  * has the file open
 942                  */
 943                 data_blob_free(&r->odb_locking_key);
 944         } else if (!NT_STATUS_IS_OK(status)) {
 945                 return status;
 946         }
 947 
 948         talloc_free(lck);
 949 
 950         talloc_set_destructor(r, pvfs_odb_retry_destructor);
 951 
 952         wait_handle = pvfs_wait_message(pvfs, req,
 953                                         MSG_PVFS_RETRY_OPEN, end_time,
 954                                         pvfs_odb_retry_callback, r);
 955         if (wait_handle == NULL) {
 956                 return NT_STATUS_NO_MEMORY;
 957         }
 958 
 959         talloc_steal(r, wait_handle);
 960 
 961         return NT_STATUS_OK;
 962 }
 963 
 964 /*
 965   retry an open after a sharing violation
 966 */
 967 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
     /* [<][>][^][v][top][bottom][index][help] */
 968                                     struct ntvfs_module_context *ntvfs,
 969                                     struct ntvfs_request *req,
 970                                     void *_io,
 971                                     void *private_data,
 972                                     enum pvfs_wait_notice reason)
 973 {
 974         union smb_open *io = talloc_get_type(_io, union smb_open);
 975         struct timeval *final_timeout = NULL;
 976         NTSTATUS status;
 977 
 978         if (private_data) {
 979                 final_timeout = talloc_get_type(private_data,
 980                                                 struct timeval);
 981         }
 982 
 983         /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
 984            just a bug in their server, but we better do the same */
 985         if (reason == PVFS_WAIT_CANCEL) {
 986                 return;
 987         }
 988 
 989         if (reason == PVFS_WAIT_TIMEOUT) {
 990                 if (final_timeout &&
 991                     !timeval_expired(final_timeout)) {
 992                         /*
 993                          * we need to retry periodictly
 994                          * after an EAGAIN as there's
 995                          * no way the kernel tell us
 996                          * an oplock is released.
 997                          */
 998                         goto retry;
 999                 }
1000                 /* if it timed out, then give the failure
1001                    immediately */
1002                 talloc_free(r);
1003                 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
1004                 req->async_states->send_fn(req);
1005                 return;
1006         }
1007 
1008 retry:
1009         talloc_free(r);
1010 
1011         /* try the open again, which could trigger another retry setup
1012            if it wants to, so we have to unmark the async flag so we
1013            will know if it does a second async reply */
1014         req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
1015 
1016         status = pvfs_open(ntvfs, req, io);
1017         if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
1018                 /* the 2nd try also replied async, so we don't send
1019                    the reply yet */
1020                 return;
1021         }
1022 
1023         /* re-mark it async, just in case someone up the chain does
1024            paranoid checking */
1025         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1026 
1027         /* send the reply up the chain */
1028         req->async_states->status = status;
1029         req->async_states->send_fn(req);
1030 }
1031 
1032 
1033 /*
1034   special handling for openx DENY_DOS semantics
1035 
1036   This function attempts a reference open using an existing handle. If its allowed,
1037   then it returns NT_STATUS_OK, otherwise it returns any other code and normal
1038   open processing continues.
1039 */
1040 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
1041                                    struct ntvfs_request *req, union smb_open *io,
1042                                    struct pvfs_file *f, struct odb_lock *lck)
1043 {
1044         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1045                                   struct pvfs_state);
1046         struct pvfs_file *f2;
1047         struct pvfs_filename *name;
1048         NTSTATUS status;
1049 
1050         /* search for an existing open with the right parameters. Note
1051            the magic ntcreatex options flag, which is set in the
1052            generic mapping code. This might look ugly, but its
1053            actually pretty much now w2k does it internally as well. 
1054            
1055            If you look at the BASE-DENYDOS test you will see that a
1056            DENY_DOS is a very special case, and in the right
1057            circumstances you actually get the _same_ handle back
1058            twice, rather than a new handle.
1059         */
1060         for (f2=pvfs->files.list;f2;f2=f2->next) {
1061                 if (f2 != f &&
1062                     f2->ntvfs->session_info == req->session_info &&
1063                     f2->ntvfs->smbpid == req->smbpid &&
1064                     (f2->handle->create_options & 
1065                      (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
1066                       NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
1067                     (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1068                     strcasecmp_m(f2->handle->name->original_name, 
1069                                io->generic.in.fname)==0) {
1070                         break;
1071                 }
1072         }
1073 
1074         if (!f2) {
1075                 return NT_STATUS_SHARING_VIOLATION;
1076         }
1077 
1078         /* quite an insane set of semantics ... */
1079         if (is_exe_filename(io->generic.in.fname) &&
1080             (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1081                 return NT_STATUS_SHARING_VIOLATION;
1082         }
1083 
1084         /*
1085           setup a reference to the existing handle
1086          */
1087         talloc_free(f->handle);
1088         f->handle = talloc_reference(f, f2->handle);
1089 
1090         talloc_free(lck);
1091 
1092         name = f->handle->name;
1093 
1094         io->generic.out.oplock_level  = OPLOCK_NONE;
1095         io->generic.out.file.ntvfs    = f->ntvfs;
1096         io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1097         io->generic.out.create_time   = name->dos.create_time;
1098         io->generic.out.access_time   = name->dos.access_time;
1099         io->generic.out.write_time    = name->dos.write_time;
1100         io->generic.out.change_time   = name->dos.change_time;
1101         io->generic.out.attrib        = name->dos.attrib;
1102         io->generic.out.alloc_size    = name->dos.alloc_size;
1103         io->generic.out.size          = name->st.st_size;
1104         io->generic.out.file_type     = FILE_TYPE_DISK;
1105         io->generic.out.ipc_state     = 0;
1106         io->generic.out.is_directory  = 0;
1107  
1108         status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1109         NT_STATUS_NOT_OK_RETURN(status);
1110 
1111         return NT_STATUS_OK;
1112 }
1113 
1114 
1115 
1116 /*
1117   setup for a open retry after a sharing violation
1118 */
1119 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
1120                                       struct ntvfs_request *req, 
1121                                       union smb_open *io,
1122                                       struct pvfs_file *f,
1123                                       struct odb_lock *lck,
1124                                       NTSTATUS parent_status)
1125 {
1126         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1127                                   struct pvfs_state);
1128         NTSTATUS status;
1129         struct timeval end_time;
1130         struct timeval *final_timeout = NULL;
1131 
1132         if (io->generic.in.create_options & 
1133             (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1134                 /* see if we can satisfy the request using the special DENY_DOS
1135                    code */
1136                 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1137                 if (NT_STATUS_IS_OK(status)) {
1138                         return status;
1139                 }
1140         }
1141 
1142         /* the retry should allocate a new file handle */
1143         talloc_free(f);
1144 
1145         if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1146                 end_time = timeval_add(&req->statistics.request_time,
1147                                        0, pvfs->sharing_violation_delay);
1148         } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1149                 end_time = timeval_add(&req->statistics.request_time,
1150                                        pvfs->oplock_break_timeout, 0);
1151         } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1152                 /*
1153                  * we got EAGAIN which means a unix application
1154                  * has an oplock or share mode
1155                  *
1156                  * we retry every 4/5 of the sharing violation delay
1157                  * to see if the unix application
1158                  * has released the oplock or share mode.
1159                  */
1160                 final_timeout = talloc(req, struct timeval);
1161                 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1162                 *final_timeout = timeval_add(&req->statistics.request_time,
1163                                              pvfs->oplock_break_timeout,
1164                                              0);
1165                 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1166                 end_time = timeval_min(final_timeout, &end_time);
1167         } else {
1168                 return NT_STATUS_INTERNAL_ERROR;
1169         }
1170 
1171         return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1172                                     final_timeout, pvfs_retry_open_sharing);
1173 }
1174 
1175 /*
1176   open a file
1177 */
1178 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
1179                    struct ntvfs_request *req, union smb_open *io)
1180 {
1181         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1182                                   struct pvfs_state);
1183         int flags = 0;
1184         struct pvfs_filename *name;
1185         struct pvfs_file *f;
1186         struct ntvfs_handle *h;
1187         NTSTATUS status;
1188         int fd;
1189         struct odb_lock *lck;
1190         uint32_t create_options;
1191         uint32_t create_options_must_ignore_mask;
1192         uint32_t share_access;
1193         uint32_t access_mask;
1194         uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1195         bool del_on_close;
1196         bool stream_existed, stream_truncate=false;
1197         uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1198         bool allow_level_II_oplock = false;
1199 
1200         /* use the generic mapping code to avoid implementing all the
1201            different open calls. */
1202         if (io->generic.level != RAW_OPEN_GENERIC &&
1203             io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1204                 return ntvfs_map_open(ntvfs, req, io);
1205         }
1206 
1207         ZERO_STRUCT(io->generic.out);
1208 
1209         create_options = io->generic.in.create_options;
1210         share_access   = io->generic.in.share_access;
1211         access_mask    = io->generic.in.access_mask;
1212 
1213         if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1214                 return NT_STATUS_INVALID_PARAMETER;
1215         }
1216 
1217         /*
1218          * These options are ignored,
1219          * but we reuse some of them as private values for the generic mapping
1220          */
1221         create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
1222         create_options_must_ignore_mask &= ~NTCREATEX_OPTIONS_PRIVATE_MASK;
1223         create_options &= ~create_options_must_ignore_mask;
1224 
1225         if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1226                 DEBUG(2,(__location__ " create_options 0x%x not supported\n", 
1227                          create_options));
1228                 return NT_STATUS_NOT_SUPPORTED;
1229         }
1230 
1231         if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
1232                 return NT_STATUS_INVALID_PARAMETER;
1233         }
1234 
1235         /* TODO: When we implement HSM, add a hook here not to pull
1236          * the actual file off tape, when this option is passed from
1237          * the client */
1238         if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1239                 /* no-op */
1240         }
1241 
1242         /* TODO: If (unlikely) Linux does a good compressed
1243          * filesystem, we might need an ioctl call for this */
1244         if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
1245                 /* no-op */
1246         }
1247 
1248         if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
1249                 create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
1250         }
1251 
1252         /* Open the file with sync, if they asked for it, but
1253            'strict sync = no' turns this client request into a no-op */
1254         if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
1255                 flags |= O_SYNC;
1256         }
1257 
1258 
1259         /* other create options are not allowed */
1260         if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1261             !(access_mask & SEC_STD_DELETE)) {
1262                 return NT_STATUS_INVALID_PARAMETER;
1263         }
1264 
1265         if (access_mask & SEC_MASK_INVALID) {
1266                 return NT_STATUS_ACCESS_DENIED;
1267         }
1268 
1269         /* what does this bit really mean?? */
1270         if (req->ctx->protocol == PROTOCOL_SMB2 &&
1271             access_mask == SEC_STD_SYNCHRONIZE) {
1272                 return NT_STATUS_ACCESS_DENIED;
1273         }
1274 
1275         if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1276                                           FILE_ATTRIBUTE_VOLUME| 
1277                                           (~FILE_ATTRIBUTE_ALL_MASK))) {
1278                 return NT_STATUS_INVALID_PARAMETER;
1279         }
1280 
1281         /* we ignore some file_attr bits */
1282         io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED | 
1283                                         FILE_ATTRIBUTE_COMPRESSED |
1284                                         FILE_ATTRIBUTE_REPARSE_POINT |
1285                                         FILE_ATTRIBUTE_SPARSE |
1286                                         FILE_ATTRIBUTE_NORMAL);
1287 
1288         /* resolve the cifs name to a posix name */
1289         status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
1290                                    PVFS_RESOLVE_STREAMS, &name);
1291         if (!NT_STATUS_IS_OK(status)) {
1292                 return status;
1293         }
1294 
1295         /* if the client specified that it must not be a directory then
1296            check that it isn't */
1297         if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1298             (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1299                 return NT_STATUS_FILE_IS_A_DIRECTORY;
1300         }
1301 
1302         /* if the client specified that it must be a directory then
1303            check that it is */
1304         if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1305             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1306                 return NT_STATUS_NOT_A_DIRECTORY;
1307         }
1308 
1309         /* directory opens are handled separately */
1310         if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1311             (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1312                 return pvfs_open_directory(pvfs, req, name, io);
1313         }
1314 
1315         /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1316            open doesn't match */
1317         io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1318 
1319         switch (io->generic.in.open_disposition) {
1320         case NTCREATEX_DISP_SUPERSEDE:
1321         case NTCREATEX_DISP_OVERWRITE_IF:
1322                 if (name->stream_name == NULL) {
1323                         flags = O_TRUNC;
1324                 } else {
1325                         stream_truncate = true;
1326                 }
1327                 create_action = NTCREATEX_ACTION_TRUNCATED;
1328                 break;
1329 
1330         case NTCREATEX_DISP_OPEN:
1331                 if (!name->stream_exists) {
1332                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1333                 }
1334                 flags = 0;
1335                 break;
1336 
1337         case NTCREATEX_DISP_OVERWRITE:
1338                 if (!name->stream_exists) {
1339                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1340                 }
1341                 if (name->stream_name == NULL) {
1342                         flags = O_TRUNC;
1343                 } else {
1344                         stream_truncate = true;
1345                 }
1346                 create_action = NTCREATEX_ACTION_TRUNCATED;
1347                 break;
1348 
1349         case NTCREATEX_DISP_CREATE:
1350                 if (name->stream_exists) {
1351                         return NT_STATUS_OBJECT_NAME_COLLISION;
1352                 }
1353                 flags = 0;
1354                 break;
1355 
1356         case NTCREATEX_DISP_OPEN_IF:
1357                 flags = 0;
1358                 break;
1359 
1360         default:
1361                 return NT_STATUS_INVALID_PARAMETER;
1362         }
1363 
1364         /* handle creating a new file separately */
1365         if (!name->exists) {
1366                 status = pvfs_create_file(pvfs, req, name, io);
1367                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1368                         return status;
1369                 }
1370 
1371                 /* we've hit a race - the file was created during this call */
1372                 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1373                         return status;
1374                 }
1375 
1376                 /* try re-resolving the name */
1377                 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1378                 if (!NT_STATUS_IS_OK(status)) {
1379                         return status;
1380                 }
1381                 /* fall through to a normal open */
1382         }
1383 
1384         if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1385             (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1386                 return NT_STATUS_CANNOT_DELETE;
1387         }
1388 
1389         /* check the security descriptor */
1390         status = pvfs_access_check(pvfs, req, name, &access_mask);
1391         NT_STATUS_NOT_OK_RETURN(status);
1392 
1393         if (io->generic.in.query_maximal_access) {
1394                 status = pvfs_access_maximal_allowed(pvfs, req, name, 
1395                                                      &io->generic.out.maximal_access);
1396                 NT_STATUS_NOT_OK_RETURN(status);
1397         }
1398 
1399         status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1400         NT_STATUS_NOT_OK_RETURN(status);
1401 
1402         f = talloc(h, struct pvfs_file);
1403         if (f == NULL) {
1404                 return NT_STATUS_NO_MEMORY;
1405         }
1406 
1407         f->handle = talloc(f, struct pvfs_file_handle);
1408         if (f->handle == NULL) {
1409                 return NT_STATUS_NO_MEMORY;
1410         }
1411 
1412         f->ntvfs         = h;
1413         f->pvfs          = pvfs;
1414         f->pending_list  = NULL;
1415         f->lock_count    = 0;
1416         f->share_access  = io->generic.in.share_access;
1417         f->access_mask   = access_mask;
1418         f->impersonation = io->generic.in.impersonation;
1419         f->notify_buffer = NULL;
1420         f->search        = NULL;
1421 
1422         f->handle->pvfs              = pvfs;
1423         f->handle->fd                = -1;
1424         f->handle->name              = talloc_steal(f->handle, name);
1425         f->handle->create_options    = io->generic.in.create_options;
1426         f->handle->seek_offset       = 0;
1427         f->handle->position          = 0;
1428         f->handle->mode              = 0;
1429         f->handle->oplock            = NULL;
1430         f->handle->have_opendb_entry = false;
1431         ZERO_STRUCT(f->handle->write_time);
1432         f->handle->open_completed    = false;
1433 
1434         /* form the lock context used for byte range locking and
1435            opendb locking */
1436         status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1437         if (!NT_STATUS_IS_OK(status)) {
1438                 return status;
1439         }
1440 
1441         status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1442         if (!NT_STATUS_IS_OK(status)) {
1443                 return status;
1444         }
1445 
1446         /* get a lock on this file before the actual open */
1447         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1448         if (lck == NULL) {
1449                 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1450                          name->full_name));
1451                 /* we were supposed to do a blocking lock, so something
1452                    is badly wrong! */
1453                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1454         }
1455 
1456         DLIST_ADD(pvfs->files.list, f);
1457 
1458         /* setup a destructor to avoid file descriptor leaks on
1459            abnormal termination */
1460         talloc_set_destructor(f, pvfs_fnum_destructor);
1461         talloc_set_destructor(f->handle, pvfs_handle_destructor);
1462 
1463         /* 
1464          * Only SMB2 takes care of the delete_on_close,
1465          * on existing files
1466          */
1467         if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1468             req->ctx->protocol == PROTOCOL_SMB2) {
1469                 del_on_close = true;
1470         } else {
1471                 del_on_close = false;
1472         }
1473 
1474         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1475                 oplock_level = OPLOCK_NONE;
1476         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1477                 oplock_level = OPLOCK_BATCH;
1478         } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1479                 oplock_level = OPLOCK_EXCLUSIVE;
1480         }
1481 
1482         if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1483                 allow_level_II_oplock = true;
1484         }
1485 
1486         /* see if we are allowed to open at the same time as existing opens */
1487         status = odb_can_open(lck, name->stream_id,
1488                               share_access, access_mask, del_on_close,
1489                               io->generic.in.open_disposition, false);
1490 
1491         /*
1492          * on a sharing violation we need to retry when the file is closed by
1493          * the other user, or after 1 second
1494          * on a non granted oplock we need to retry when the file is closed by
1495          * the other user, or after 30 seconds
1496         */
1497         if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1498              NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1499             (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1500                 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1501         }
1502 
1503         if (!NT_STATUS_IS_OK(status)) {
1504                 talloc_free(lck);
1505                 return status;
1506         }
1507 
1508         if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1509                 flags |= O_RDWR;
1510         } else {
1511                 flags |= O_RDONLY;
1512         }
1513 
1514         /* do the actual open */
1515         fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1516         if (fd == -1) {
1517                 status = pvfs_map_errno(f->pvfs, errno);
1518 
1519                 /*
1520                  * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1521                  */
1522                 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1523                     (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1524                         return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1525                 }
1526 
1527                 talloc_free(lck);
1528                 return status;
1529         }
1530 
1531         f->handle->fd = fd;
1532 
1533         /* now really mark the file as open */
1534         status = odb_open_file(lck, f->handle, name->full_name,
1535                                &f->handle->fd, name->dos.write_time,
1536                                allow_level_II_oplock,
1537                                oplock_level, &oplock_granted);
1538 
1539         if (!NT_STATUS_IS_OK(status)) {
1540                 talloc_free(lck);
1541                 return status;
1542         }
1543 
1544         f->handle->have_opendb_entry = true;
1545 
1546         if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1547                 oplock_granted = OPLOCK_BATCH;
1548         } else if (oplock_granted != OPLOCK_NONE) {
1549                 status = pvfs_setup_oplock(f, oplock_granted);
1550                 if (!NT_STATUS_IS_OK(status)) {
1551                         talloc_free(lck);
1552                         return status;
1553                 }
1554         }
1555 
1556         stream_existed = name->stream_exists;
1557 
1558         /* if this was a stream create then create the stream as well */
1559         if (!name->stream_exists) {
1560                 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1561                 if (!NT_STATUS_IS_OK(status)) {
1562                         talloc_free(lck);
1563                         return status;
1564                 }
1565                 if (stream_truncate) {
1566                         status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1567                         if (!NT_STATUS_IS_OK(status)) {
1568                                 talloc_free(lck);
1569                                 return status;
1570                         }
1571                 }
1572         }
1573 
1574         /* re-resolve the open fd */
1575         status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1576         if (!NT_STATUS_IS_OK(status)) {
1577                 talloc_free(lck);
1578                 return status;
1579         }
1580 
1581         if (f->handle->name->stream_id == 0 &&
1582             (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1583              io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1584                 /* for overwrite we need to replace file permissions */
1585                 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1586                 mode_t mode = pvfs_fileperms(pvfs, attrib);
1587                 if (fchmod(fd, mode) == -1) {
1588                         talloc_free(lck);
1589                         return pvfs_map_errno(pvfs, errno);
1590                 }
1591                 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1592                 name->dos.attrib = attrib;
1593                 status = pvfs_dosattrib_save(pvfs, name, fd);
1594                 if (!NT_STATUS_IS_OK(status)) {
1595                         talloc_free(lck);
1596                         return status;
1597                 }
1598         }
1599             
1600         talloc_free(lck);
1601 
1602         status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1603         NT_STATUS_NOT_OK_RETURN(status);
1604 
1605         /* mark the open as having completed fully, so delete on close
1606            can now be used */
1607         f->handle->open_completed     = true;
1608 
1609         io->generic.out.oplock_level  = oplock_granted;
1610         io->generic.out.file.ntvfs    = h;
1611         io->generic.out.create_action = stream_existed?
1612                 create_action:NTCREATEX_ACTION_CREATED;
1613         
1614         io->generic.out.create_time   = name->dos.create_time;
1615         io->generic.out.access_time   = name->dos.access_time;
1616         io->generic.out.write_time    = name->dos.write_time;
1617         io->generic.out.change_time   = name->dos.change_time;
1618         io->generic.out.attrib        = name->dos.attrib;
1619         io->generic.out.alloc_size    = name->dos.alloc_size;
1620         io->generic.out.size          = name->st.st_size;
1621         io->generic.out.file_type     = FILE_TYPE_DISK;
1622         io->generic.out.ipc_state     = 0;
1623         io->generic.out.is_directory  = 0;
1624 
1625         return NT_STATUS_OK;
1626 }
1627 
1628 
1629 /*
1630   close a file
1631 */
1632 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
1633                     struct ntvfs_request *req, union smb_close *io)
1634 {
1635         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1636                                   struct pvfs_state);
1637         struct pvfs_file *f;
1638 
1639         if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1640                 return NT_STATUS_DOS(ERRSRV, ERRerror);
1641         }
1642 
1643         if (io->generic.level != RAW_CLOSE_GENERIC) {
1644                 return ntvfs_map_close(ntvfs, req, io);
1645         }
1646 
1647         f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1648         if (!f) {
1649                 return NT_STATUS_INVALID_HANDLE;
1650         }
1651 
1652         if (!null_time(io->generic.in.write_time)) {
1653                 f->handle->write_time.update_forced = false;
1654                 f->handle->write_time.update_on_close = true;
1655                 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1656         }
1657 
1658         if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1659                 struct pvfs_filename *name;
1660                 NTSTATUS status;
1661                 struct pvfs_file_handle *h = f->handle;
1662 
1663                 status = pvfs_resolve_name_handle(pvfs, h);
1664                 if (!NT_STATUS_IS_OK(status)) {
1665                         return status;
1666                 }
1667                 name = h->name;
1668 
1669                 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1670                 io->generic.out.create_time = name->dos.create_time;
1671                 io->generic.out.access_time = name->dos.access_time;
1672                 io->generic.out.write_time  = name->dos.write_time;
1673                 io->generic.out.change_time = name->dos.change_time;
1674                 io->generic.out.alloc_size  = name->dos.alloc_size;
1675                 io->generic.out.size        = name->st.st_size;
1676                 io->generic.out.file_attr   = name->dos.attrib;         
1677         } else {
1678                 ZERO_STRUCT(io->generic.out);
1679         }
1680 
1681         talloc_free(f);
1682 
1683         return NT_STATUS_OK;
1684 }
1685 
1686 
1687 /*
1688   logoff - close all file descriptors open by a vuid
1689 */
1690 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
1691                      struct ntvfs_request *req)
1692 {
1693         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1694                                   struct pvfs_state);
1695         struct pvfs_file *f, *next;
1696 
1697         for (f=pvfs->files.list;f;f=next) {
1698                 next = f->next;
1699                 if (f->ntvfs->session_info == req->session_info) {
1700                         talloc_free(f);
1701                 }
1702         }
1703 
1704         return NT_STATUS_OK;
1705 }
1706 
1707 
1708 /*
1709   exit - close files for the current pid
1710 */
1711 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
1712                    struct ntvfs_request *req)
1713 {
1714         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1715                                   struct pvfs_state);
1716         struct pvfs_file *f, *next;
1717 
1718         for (f=pvfs->files.list;f;f=next) {
1719                 next = f->next;
1720                 if (f->ntvfs->session_info == req->session_info &&
1721                     f->ntvfs->smbpid == req->smbpid) {
1722                         talloc_free(f);
1723                 }
1724         }
1725 
1726         return NT_STATUS_OK;
1727 }
1728 
1729 
1730 /*
1731   change the delete on close flag on an already open file
1732 */
1733 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
     /* [<][>][^][v][top][bottom][index][help] */
1734                                   struct ntvfs_request *req, 
1735                                   struct pvfs_file *f, bool del_on_close)
1736 {
1737         struct odb_lock *lck;
1738         NTSTATUS status;
1739 
1740         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1741                 return NT_STATUS_CANNOT_DELETE;
1742         }
1743         
1744         if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1745             !pvfs_directory_empty(pvfs, f->handle->name)) {
1746                 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1747         }
1748 
1749         if (del_on_close) {
1750                 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1751         } else {
1752                 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1753         }
1754         
1755         lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1756         if (lck == NULL) {
1757                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1758         }
1759 
1760         status = odb_set_delete_on_close(lck, del_on_close);
1761 
1762         talloc_free(lck);
1763 
1764         return status;
1765 }
1766 
1767 
1768 /*
1769   determine if a file can be deleted, or if it is prevented by an
1770   already open file
1771 */
1772 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
1773                          struct ntvfs_request *req,
1774                          struct pvfs_filename *name,
1775                          struct odb_lock **lckp)
1776 {
1777         NTSTATUS status;
1778         DATA_BLOB key;
1779         struct odb_lock *lck;
1780         uint32_t share_access;
1781         uint32_t access_mask;
1782         bool delete_on_close;
1783 
1784         status = pvfs_locking_key(name, name, &key);
1785         if (!NT_STATUS_IS_OK(status)) {
1786                 return NT_STATUS_NO_MEMORY;
1787         }
1788 
1789         lck = odb_lock(req, pvfs->odb_context, &key);
1790         if (lck == NULL) {
1791                 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1792                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1793         }
1794 
1795         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1796                           NTCREATEX_SHARE_ACCESS_WRITE |
1797                           NTCREATEX_SHARE_ACCESS_DELETE;
1798         access_mask     = SEC_STD_DELETE;
1799         delete_on_close = true;
1800 
1801         status = odb_can_open(lck, name->stream_id,
1802                               share_access, access_mask, delete_on_close,
1803                               NTCREATEX_DISP_OPEN, false);
1804 
1805         if (NT_STATUS_IS_OK(status)) {
1806                 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1807         }
1808 
1809         /*
1810          * if it's a sharing violation or we got no oplock
1811          * only keep the lock if the caller requested access
1812          * to the lock
1813          */
1814         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1815             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1816                 if (lckp) {
1817                         *lckp = lck;
1818                 } else {
1819                         talloc_free(lck);
1820                 }
1821         } else if (!NT_STATUS_IS_OK(status)) {
1822                 talloc_free(lck);
1823                 if (lckp) {
1824                         *lckp = NULL;
1825                 }
1826         } else if (lckp) {
1827                 *lckp = lck;
1828         }
1829 
1830         return status;
1831 }
1832 
1833 /*
1834   determine if a file can be renamed, or if it is prevented by an
1835   already open file
1836 */
1837 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
1838                          struct ntvfs_request *req,
1839                          struct pvfs_filename *name,
1840                          struct odb_lock **lckp)
1841 {
1842         NTSTATUS status;
1843         DATA_BLOB key;
1844         struct odb_lock *lck;
1845         uint32_t share_access;
1846         uint32_t access_mask;
1847         bool delete_on_close;
1848 
1849         status = pvfs_locking_key(name, name, &key);
1850         if (!NT_STATUS_IS_OK(status)) {
1851                 return NT_STATUS_NO_MEMORY;
1852         }
1853 
1854         lck = odb_lock(req, pvfs->odb_context, &key);
1855         if (lck == NULL) {
1856                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1857                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1858         }
1859 
1860         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1861                           NTCREATEX_SHARE_ACCESS_WRITE;
1862         access_mask     = SEC_STD_DELETE;
1863         delete_on_close = false;
1864 
1865         status = odb_can_open(lck, name->stream_id,
1866                               share_access, access_mask, delete_on_close,
1867                               NTCREATEX_DISP_OPEN, false);
1868 
1869         /*
1870          * if it's a sharing violation or we got no oplock
1871          * only keep the lock if the caller requested access
1872          * to the lock
1873          */
1874         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1875             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1876                 if (lckp) {
1877                         *lckp = lck;
1878                 } else {
1879                         talloc_free(lck);
1880                 }
1881         } else if (!NT_STATUS_IS_OK(status)) {
1882                 talloc_free(lck);
1883                 if (lckp) {
1884                         *lckp = NULL;
1885                 }
1886         } else if (lckp) {
1887                 *lckp = lck;
1888         }
1889 
1890         return status;
1891 }
1892 
1893 /*
1894   determine if the file size of a file can be changed,
1895   or if it is prevented by an already open file
1896 */
1897 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
     /* [<][>][^][v][top][bottom][index][help] */
1898                                    struct ntvfs_request *req,
1899                                    struct pvfs_filename *name,
1900                                    struct odb_lock **lckp)
1901 {
1902         NTSTATUS status;
1903         DATA_BLOB key;
1904         struct odb_lock *lck;
1905         uint32_t share_access;
1906         uint32_t access_mask;
1907         bool break_to_none;
1908         bool delete_on_close;
1909 
1910         status = pvfs_locking_key(name, name, &key);
1911         if (!NT_STATUS_IS_OK(status)) {
1912                 return NT_STATUS_NO_MEMORY;
1913         }
1914 
1915         lck = odb_lock(req, pvfs->odb_context, &key);
1916         if (lck == NULL) {
1917                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1918                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1919         }
1920 
1921         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1922                           NTCREATEX_SHARE_ACCESS_WRITE |
1923                           NTCREATEX_SHARE_ACCESS_DELETE;
1924         /*
1925          * I would have thought that we would need to pass
1926          * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1927          *
1928          * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1929          * to set the filesize.
1930          *
1931          * --metze
1932          */
1933         access_mask     = SEC_FILE_WRITE_ATTRIBUTE;
1934         delete_on_close = false;
1935         break_to_none   = true;
1936 
1937         status = odb_can_open(lck, name->stream_id,
1938                               share_access, access_mask, delete_on_close,
1939                               NTCREATEX_DISP_OPEN, break_to_none);
1940 
1941         /*
1942          * if it's a sharing violation or we got no oplock
1943          * only keep the lock if the caller requested access
1944          * to the lock
1945          */
1946         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1947             NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1948                 if (lckp) {
1949                         *lckp = lck;
1950                 } else {
1951                         talloc_free(lck);
1952                 }
1953         } else if (!NT_STATUS_IS_OK(status)) {
1954                 talloc_free(lck);
1955                 if (lckp) {
1956                         *lckp = NULL;
1957                 }
1958         } else if (lckp) {
1959                 *lckp = lck;
1960         }
1961 
1962         return status;
1963 }
1964 
1965 /*
1966   determine if file meta data can be accessed, or if it is prevented by an
1967   already open file
1968 */
1969 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
1970                        struct ntvfs_request *req,
1971                        struct pvfs_filename *name)
1972 {
1973         NTSTATUS status;
1974         DATA_BLOB key;
1975         struct odb_lock *lck;
1976         uint32_t share_access;
1977         uint32_t access_mask;
1978         bool delete_on_close;
1979 
1980         status = pvfs_locking_key(name, name, &key);
1981         if (!NT_STATUS_IS_OK(status)) {
1982                 return NT_STATUS_NO_MEMORY;
1983         }
1984 
1985         lck = odb_lock(req, pvfs->odb_context, &key);
1986         if (lck == NULL) {
1987                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1988                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1989         }
1990 
1991         share_access    = NTCREATEX_SHARE_ACCESS_READ |
1992                           NTCREATEX_SHARE_ACCESS_WRITE;
1993         access_mask     = SEC_FILE_READ_ATTRIBUTE;
1994         delete_on_close = false;
1995 
1996         status = odb_can_open(lck, name->stream_id,
1997                               share_access, access_mask, delete_on_close,
1998                               NTCREATEX_DISP_OPEN, false);
1999 
2000         if (!NT_STATUS_IS_OK(status)) {
2001                 talloc_free(lck);
2002         }
2003 
2004         return status;
2005 }
2006 
2007 
2008 /*
2009   determine if delete on close is set on 
2010 */
2011 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
     /* [<][>][^][v][top][bottom][index][help] */
2012 {
2013         NTSTATUS status;
2014         bool del_on_close;
2015 
2016         status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key, 
2017                                     &del_on_close, NULL);
2018         if (!NT_STATUS_IS_OK(status)) {
2019                 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2020                 return false;
2021         }
2022 
2023         return del_on_close;
2024 }

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