root/source4/ntvfs/posix/pvfs_setfileinfo.c

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

DEFINITIONS

This source file includes following definitions.
  1. pvfs_setfileinfo_access
  2. pvfs_setfileinfo_rename_stream
  3. pvfs_setfileinfo_rename
  4. pvfs_setfileinfo_ea_set
  5. pvfs_setfileinfo
  6. pvfs_retry_setpathinfo
  7. pvfs_setpathinfo_setup_retry
  8. pvfs_setpathinfo

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    POSIX NTVFS backend - setfileinfo
   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/time.h"
  25 #include "librpc/gen_ndr/xattr.h"
  26 
  27 
  28 /*
  29   determine what access bits are needed for a call
  30 */
  31 static uint32_t pvfs_setfileinfo_access(union smb_setfileinfo *info)
     /* [<][>][^][v][top][bottom][index][help] */
  32 {
  33         uint32_t needed;
  34 
  35         switch (info->generic.level) {
  36         case RAW_SFILEINFO_EA_SET:
  37                 needed = SEC_FILE_WRITE_EA;
  38                 break;
  39 
  40         case RAW_SFILEINFO_DISPOSITION_INFO:
  41         case RAW_SFILEINFO_DISPOSITION_INFORMATION:
  42                 needed = SEC_STD_DELETE;
  43                 break;
  44 
  45         case RAW_SFILEINFO_END_OF_FILE_INFO:
  46                 needed = SEC_FILE_WRITE_DATA;
  47                 break;
  48 
  49         case RAW_SFILEINFO_POSITION_INFORMATION:
  50                 needed = 0;
  51                 break;
  52 
  53         case RAW_SFILEINFO_SEC_DESC:
  54                 needed = 0;
  55                 if (info->set_secdesc.in.secinfo_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
  56                         needed |= SEC_STD_WRITE_OWNER;
  57                 }
  58                 if (info->set_secdesc.in.secinfo_flags & SECINFO_DACL) {
  59                         needed |= SEC_STD_WRITE_DAC;
  60                 }
  61                 if (info->set_secdesc.in.secinfo_flags & SECINFO_SACL) {
  62                         needed |= SEC_FLAG_SYSTEM_SECURITY;
  63                 }
  64                 break;
  65 
  66         case RAW_SFILEINFO_RENAME_INFORMATION:
  67         case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
  68                 needed = SEC_STD_DELETE;
  69                 break;
  70 
  71         default:
  72                 needed = SEC_FILE_WRITE_ATTRIBUTE;
  73                 break;
  74         }
  75 
  76         return needed;
  77 }
  78 
  79 /*
  80   rename_information level for streams
  81 */
  82 static NTSTATUS pvfs_setfileinfo_rename_stream(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
  83                                                struct ntvfs_request *req, 
  84                                                struct pvfs_filename *name,
  85                                                int fd,
  86                                                DATA_BLOB *odb_locking_key,
  87                                                union smb_setfileinfo *info)
  88 {
  89         NTSTATUS status;
  90         struct odb_lock *lck = NULL;
  91 
  92         if (info->rename_information.in.new_name[0] != ':') {
  93                 return NT_STATUS_INVALID_PARAMETER;
  94         }
  95 
  96         status = pvfs_access_check_simple(pvfs, req, name, SEC_FILE_WRITE_ATTRIBUTE);
  97         if (!NT_STATUS_IS_OK(status)) {
  98                 return status;
  99         }
 100 
 101         lck = odb_lock(req, pvfs->odb_context, odb_locking_key);
 102         if (lck == NULL) {
 103                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
 104                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
 105         }
 106 
 107 
 108         status = pvfs_stream_rename(pvfs, name, fd, 
 109                                     info->rename_information.in.new_name+1);
 110         return status;
 111 }
 112 
 113 /*
 114   rename_information level
 115 */
 116 static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 117                                         struct ntvfs_request *req, 
 118                                         struct pvfs_filename *name,
 119                                         int fd,
 120                                         DATA_BLOB *odb_locking_key,
 121                                         union smb_setfileinfo *info)
 122 {
 123         NTSTATUS status;
 124         struct pvfs_filename *name2;
 125         char *new_name, *p;
 126         struct odb_lock *lck = NULL;
 127 
 128         /* renames are only allowed within a directory */
 129         if (strchr_m(info->rename_information.in.new_name, '\\') &&
 130             (req->ctx->protocol != PROTOCOL_SMB2)) {
 131                 return NT_STATUS_NOT_SUPPORTED;
 132         }
 133 
 134         /* handle stream renames specially */
 135         if (name->stream_name) {
 136                 return pvfs_setfileinfo_rename_stream(pvfs, req, name, fd, 
 137                                                       odb_locking_key, info);
 138         }
 139 
 140         /* w2k3 does not appear to allow relative rename. On SMB2, vista sends it sometimes,
 141            but I suspect it is just uninitialised memory */
 142         if (info->rename_information.in.root_fid != 0 && 
 143             (req->ctx->protocol != PROTOCOL_SMB2)) {
 144                 return NT_STATUS_INVALID_PARAMETER;
 145         }
 146 
 147         /* construct the fully qualified windows name for the new file name */
 148         if (req->ctx->protocol == PROTOCOL_SMB2) {
 149                 /* SMB2 sends the full path of the new name */
 150                 new_name = talloc_asprintf(req, "\\%s", info->rename_information.in.new_name);
 151         } else {
 152                 new_name = talloc_strdup(req, name->original_name);
 153                 if (new_name == NULL) {
 154                         return NT_STATUS_NO_MEMORY;
 155                 }
 156                 p = strrchr_m(new_name, '\\');
 157                 if (p == NULL) {
 158                         return NT_STATUS_OBJECT_NAME_INVALID;
 159                 } else {
 160                         *p = 0;
 161                 }
 162 
 163                 new_name = talloc_asprintf(req, "%s\\%s", new_name,
 164                                            info->rename_information.in.new_name);
 165         }
 166         if (new_name == NULL) {
 167                 return NT_STATUS_NO_MEMORY;
 168         }
 169 
 170         /* resolve the new name */
 171         status = pvfs_resolve_name(pvfs, name, new_name, 0, &name2);
 172         if (!NT_STATUS_IS_OK(status)) {
 173                 return status;
 174         }
 175 
 176         /* if the destination exists, then check the rename is allowed */
 177         if (name2->exists) {
 178                 if (strcmp(name2->full_name, name->full_name) == 0) {
 179                         /* rename to same name is null-op */
 180                         return NT_STATUS_OK;
 181                 }
 182 
 183                 if (!info->rename_information.in.overwrite) {
 184                         return NT_STATUS_OBJECT_NAME_COLLISION;
 185                 }
 186 
 187                 status = pvfs_can_delete(pvfs, req, name2, NULL);
 188                 if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
 189                         return NT_STATUS_ACCESS_DENIED;
 190                 }
 191                 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
 192                         return NT_STATUS_ACCESS_DENIED;
 193                 }
 194                 if (!NT_STATUS_IS_OK(status)) {
 195                         return status;
 196                 }
 197         }
 198 
 199         status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
 200         if (!NT_STATUS_IS_OK(status)) {
 201                 return status;
 202         }
 203 
 204         lck = odb_lock(req, pvfs->odb_context, odb_locking_key);
 205         if (lck == NULL) {
 206                 DEBUG(0,("Unable to lock opendb for can_stat\n"));
 207                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
 208         }
 209 
 210         status = pvfs_do_rename(pvfs, lck, name, name2->full_name);
 211         talloc_free(lck);
 212         NT_STATUS_NOT_OK_RETURN(status);
 213         if (NT_STATUS_IS_OK(status)) {
 214                 name->full_name = talloc_steal(name, name2->full_name);
 215                 name->original_name = talloc_steal(name, name2->original_name);
 216         }
 217 
 218         return NT_STATUS_OK;
 219 }
 220 
 221 /*
 222   add a single DOS EA
 223 */
 224 NTSTATUS pvfs_setfileinfo_ea_set(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 225                                  struct pvfs_filename *name,
 226                                  int fd, uint16_t num_eas,
 227                                  struct ea_struct *eas)
 228 {
 229         struct xattr_DosEAs *ealist;
 230         int i, j;
 231         NTSTATUS status;
 232 
 233         if (num_eas == 0) {
 234                 return NT_STATUS_OK;
 235         }
 236 
 237         if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
 238                 return NT_STATUS_NOT_SUPPORTED;
 239         }
 240 
 241         ealist = talloc(name, struct xattr_DosEAs);
 242 
 243         /* load the current list */
 244         status = pvfs_doseas_load(pvfs, name, fd, ealist);
 245         if (!NT_STATUS_IS_OK(status)) {
 246                 return status;
 247         }
 248 
 249         for (j=0;j<num_eas;j++) {
 250                 struct ea_struct *ea = &eas[j];
 251                 /* see if its already there */
 252                 for (i=0;i<ealist->num_eas;i++) {
 253                         if (strcasecmp_m(ealist->eas[i].name, ea->name.s) == 0) {
 254                                 ealist->eas[i].value = ea->value;
 255                                 break;
 256                         }
 257                 }
 258 
 259                 if (i==ealist->num_eas) {
 260                         /* add it */
 261                         ealist->eas = talloc_realloc(ealist, ealist->eas, 
 262                                                        struct xattr_EA, 
 263                                                        ealist->num_eas+1);
 264                         if (ealist->eas == NULL) {
 265                                 return NT_STATUS_NO_MEMORY;
 266                         }
 267                         ealist->eas[i].name = ea->name.s;
 268                         ealist->eas[i].value = ea->value;
 269                         ealist->num_eas++;
 270                 }
 271         }
 272         
 273         /* pull out any null EAs */
 274         for (i=0;i<ealist->num_eas;i++) {
 275                 if (ealist->eas[i].value.length == 0) {
 276                         memmove(&ealist->eas[i],
 277                                 &ealist->eas[i+1],
 278                                 (ealist->num_eas-(i+1)) * sizeof(ealist->eas[i]));
 279                         ealist->num_eas--;
 280                         i--;
 281                 }
 282         }
 283 
 284         status = pvfs_doseas_save(pvfs, name, fd, ealist);
 285         if (!NT_STATUS_IS_OK(status)) {
 286                 return status;
 287         }
 288 
 289         notify_trigger(pvfs->notify_context, 
 290                        NOTIFY_ACTION_MODIFIED, 
 291                        FILE_NOTIFY_CHANGE_EA,
 292                        name->full_name);
 293 
 294         name->dos.ea_size = 4;
 295         for (i=0;i<ealist->num_eas;i++) {
 296                 name->dos.ea_size += 4 + strlen(ealist->eas[i].name)+1 + 
 297                         ealist->eas[i].value.length;
 298         }
 299 
 300         /* update the ea_size attrib */
 301         return pvfs_dosattrib_save(pvfs, name, fd);
 302 }
 303 
 304 /*
 305   set info on a open file
 306 */
 307 NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 308                           struct ntvfs_request *req, 
 309                           union smb_setfileinfo *info)
 310 {
 311         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
 312                                   struct pvfs_state);
 313         struct pvfs_file *f;
 314         struct pvfs_file_handle *h;
 315         struct pvfs_filename newstats;
 316         NTSTATUS status;
 317         uint32_t access_needed;
 318         uint32_t change_mask = 0;
 319 
 320         f = pvfs_find_fd(pvfs, req, info->generic.in.file.ntvfs);
 321         if (!f) {
 322                 return NT_STATUS_INVALID_HANDLE;
 323         }
 324 
 325         h = f->handle;
 326 
 327         access_needed = pvfs_setfileinfo_access(info);
 328         if ((f->access_mask & access_needed) != access_needed) {
 329                 return NT_STATUS_ACCESS_DENIED;
 330         }
 331 
 332         /* update the file information */
 333         status = pvfs_resolve_name_handle(pvfs, h);
 334         if (!NT_STATUS_IS_OK(status)) {
 335                 return status;
 336         }
 337 
 338         /* we take a copy of the current file stats, then update
 339            newstats in each of the elements below. At the end we
 340            compare, and make any changes needed */
 341         newstats = *h->name;
 342 
 343         switch (info->generic.level) {
 344         case RAW_SFILEINFO_SETATTR:
 345                 if (!null_time(info->setattr.in.write_time)) {
 346                         unix_to_nt_time(&newstats.dos.write_time, info->setattr.in.write_time);
 347                 }
 348                 if (info->setattr.in.attrib != FILE_ATTRIBUTE_NORMAL) {
 349                         newstats.dos.attrib = info->setattr.in.attrib;
 350                 }
 351                 break;
 352 
 353         case RAW_SFILEINFO_SETATTRE:
 354         case RAW_SFILEINFO_STANDARD:
 355                 if (!null_time(info->setattre.in.create_time)) {
 356                         unix_to_nt_time(&newstats.dos.create_time, info->setattre.in.create_time);
 357                 }
 358                 if (!null_time(info->setattre.in.access_time)) {
 359                         unix_to_nt_time(&newstats.dos.access_time, info->setattre.in.access_time);
 360                 }
 361                 if (!null_time(info->setattre.in.write_time)) {
 362                         unix_to_nt_time(&newstats.dos.write_time, info->setattre.in.write_time);
 363                 }
 364                 break;
 365 
 366         case RAW_SFILEINFO_EA_SET:
 367                 return pvfs_setfileinfo_ea_set(pvfs, h->name, h->fd, 
 368                                                info->ea_set.in.num_eas,
 369                                                info->ea_set.in.eas);
 370 
 371         case RAW_SFILEINFO_BASIC_INFO:
 372         case RAW_SFILEINFO_BASIC_INFORMATION:
 373                 if (!null_nttime(info->basic_info.in.create_time)) {
 374                         newstats.dos.create_time = info->basic_info.in.create_time;
 375                 }
 376                 if (!null_nttime(info->basic_info.in.access_time)) {
 377                         newstats.dos.access_time = info->basic_info.in.access_time;
 378                 }
 379                 if (!null_nttime(info->basic_info.in.write_time)) {
 380                         newstats.dos.write_time = info->basic_info.in.write_time;
 381                 }
 382                 if (!null_nttime(info->basic_info.in.change_time)) {
 383                         newstats.dos.change_time = info->basic_info.in.change_time;
 384                 }
 385                 if (info->basic_info.in.attrib != 0) {
 386                         newstats.dos.attrib = info->basic_info.in.attrib;
 387                 }
 388                 break;
 389 
 390         case RAW_SFILEINFO_DISPOSITION_INFO:
 391         case RAW_SFILEINFO_DISPOSITION_INFORMATION:
 392                 return pvfs_set_delete_on_close(pvfs, req, f, 
 393                                                 info->disposition_info.in.delete_on_close);
 394 
 395         case RAW_SFILEINFO_ALLOCATION_INFO:
 396         case RAW_SFILEINFO_ALLOCATION_INFORMATION:
 397                 status = pvfs_break_level2_oplocks(f);
 398                 NT_STATUS_NOT_OK_RETURN(status);
 399 
 400                 newstats.dos.alloc_size = info->allocation_info.in.alloc_size;
 401                 if (newstats.dos.alloc_size < newstats.st.st_size) {
 402                         newstats.st.st_size = newstats.dos.alloc_size;
 403                 }
 404                 newstats.dos.alloc_size = pvfs_round_alloc_size(pvfs, 
 405                                                                 newstats.dos.alloc_size);
 406                 break;
 407 
 408         case RAW_SFILEINFO_END_OF_FILE_INFO:
 409         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
 410                 status = pvfs_break_level2_oplocks(f);
 411                 NT_STATUS_NOT_OK_RETURN(status);
 412 
 413                 newstats.st.st_size = info->end_of_file_info.in.size;
 414                 break;
 415 
 416         case RAW_SFILEINFO_POSITION_INFORMATION:
 417                 h->position = info->position_information.in.position;
 418                 break;
 419 
 420         case RAW_SFILEINFO_MODE_INFORMATION:
 421                 /* this one is a puzzle */
 422                 if (info->mode_information.in.mode != 0 &&
 423                     info->mode_information.in.mode != 2 &&
 424                     info->mode_information.in.mode != 4 &&
 425                     info->mode_information.in.mode != 6) {
 426                         return NT_STATUS_INVALID_PARAMETER;
 427                 }
 428                 h->mode = info->mode_information.in.mode;
 429                 break;
 430 
 431         case RAW_SFILEINFO_RENAME_INFORMATION:
 432         case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
 433                 return pvfs_setfileinfo_rename(pvfs, req, h->name, f->handle->fd,
 434                                                &h->odb_locking_key,
 435                                                info);
 436 
 437         case RAW_SFILEINFO_SEC_DESC:
 438                 notify_trigger(pvfs->notify_context, 
 439                                NOTIFY_ACTION_MODIFIED, 
 440                                FILE_NOTIFY_CHANGE_SECURITY,
 441                                h->name->full_name);
 442                 return pvfs_acl_set(pvfs, req, h->name, h->fd, f->access_mask, info);
 443 
 444         default:
 445                 return NT_STATUS_INVALID_LEVEL;
 446         }
 447 
 448         /* possibly change the file size */
 449         if (newstats.st.st_size != h->name->st.st_size) {
 450                 if (h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
 451                         return NT_STATUS_FILE_IS_A_DIRECTORY;
 452                 }
 453                 if (h->name->stream_name) {
 454                         status = pvfs_stream_truncate(pvfs, h->name, h->fd, newstats.st.st_size);
 455                         if (!NT_STATUS_IS_OK(status)) {
 456                                 return status;
 457                         }
 458                         
 459                         change_mask |= FILE_NOTIFY_CHANGE_STREAM_SIZE;
 460                 } else {
 461                         int ret;
 462                         if (f->access_mask & 
 463                             (SEC_FILE_WRITE_DATA|SEC_FILE_APPEND_DATA)) {
 464                                 ret = ftruncate(h->fd, newstats.st.st_size);
 465                         } else {
 466                                 ret = truncate(h->name->full_name, newstats.st.st_size);
 467                         }
 468                         if (ret == -1) {
 469                                 return pvfs_map_errno(pvfs, errno);
 470                         }
 471                         change_mask |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
 472                 }
 473         }
 474 
 475         /* possibly change the file timestamps */
 476         if (newstats.dos.create_time != h->name->dos.create_time) {
 477                 change_mask |= FILE_NOTIFY_CHANGE_CREATION;
 478         }
 479         if (newstats.dos.access_time != h->name->dos.access_time) {
 480                 change_mask |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
 481         }
 482         if (newstats.dos.write_time != h->name->dos.write_time) {
 483                 change_mask |= FILE_NOTIFY_CHANGE_LAST_WRITE;
 484         }
 485         if ((change_mask & FILE_NOTIFY_CHANGE_LAST_ACCESS) ||
 486             (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE)) {
 487                 struct timeval tv[2];
 488 
 489                 nttime_to_timeval(&tv[0], newstats.dos.access_time);
 490                 nttime_to_timeval(&tv[1], newstats.dos.write_time);
 491 
 492                 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
 493                         if (utimes(h->name->full_name, tv) == -1) {
 494                                 DEBUG(0,("pvfs_setfileinfo: utimes() failed '%s' - %s\n",
 495                                          h->name->full_name, strerror(errno)));
 496                                 return pvfs_map_errno(pvfs, errno);
 497                         }
 498                 }
 499         }
 500         if (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE) {
 501                 struct odb_lock *lck;
 502 
 503                 lck = odb_lock(req, h->pvfs->odb_context, &h->odb_locking_key);
 504                 if (lck == NULL) {
 505                         DEBUG(0,("Unable to lock opendb for write time update\n"));
 506                         return NT_STATUS_INTERNAL_ERROR;
 507                 }
 508 
 509                 status = odb_set_write_time(lck, newstats.dos.write_time, true);
 510                 if (!NT_STATUS_IS_OK(status)) {
 511                         DEBUG(0,("Unable to update write time: %s\n",
 512                                 nt_errstr(status)));
 513                         talloc_free(lck);
 514                         return status;
 515                 }
 516 
 517                 talloc_free(lck);
 518 
 519                 h->write_time.update_forced = true;
 520                 h->write_time.update_on_close = false;
 521                 talloc_free(h->write_time.update_event);
 522                 h->write_time.update_event = NULL;
 523         }
 524 
 525         /* possibly change the attribute */
 526         if (newstats.dos.attrib != h->name->dos.attrib) {
 527                 mode_t mode;
 528                 if ((newstats.dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
 529                     !(h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
 530                         return NT_STATUS_INVALID_PARAMETER;
 531                 }
 532                 mode = pvfs_fileperms(pvfs, newstats.dos.attrib);
 533                 if (!(h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
 534                         if (fchmod(h->fd, mode) == -1) {
 535                                 return pvfs_map_errno(pvfs, errno);
 536                         }
 537                 }
 538                 change_mask |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
 539         }
 540 
 541         *h->name = newstats;
 542 
 543         notify_trigger(pvfs->notify_context, 
 544                        NOTIFY_ACTION_MODIFIED, 
 545                        change_mask,
 546                        h->name->full_name);
 547 
 548         return pvfs_dosattrib_save(pvfs, h->name, h->fd);
 549 }
 550 
 551 /*
 552   retry an open after a sharing violation
 553 */
 554 static void pvfs_retry_setpathinfo(struct pvfs_odb_retry *r,
     /* [<][>][^][v][top][bottom][index][help] */
 555                                    struct ntvfs_module_context *ntvfs,
 556                                    struct ntvfs_request *req,
 557                                    void *_info,
 558                                    void *private_data,
 559                                    enum pvfs_wait_notice reason)
 560 {
 561         union smb_setfileinfo *info = talloc_get_type(_info,
 562                                       union smb_setfileinfo);
 563         NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
 564 
 565         talloc_free(r);
 566 
 567         switch (reason) {
 568         case PVFS_WAIT_CANCEL:
 569 /*TODO*/
 570                 status = NT_STATUS_CANCELLED;
 571                 break;
 572         case PVFS_WAIT_TIMEOUT:
 573                 /* if it timed out, then give the failure
 574                    immediately */
 575 /*TODO*/
 576                 status = NT_STATUS_SHARING_VIOLATION;
 577                 break;
 578         case PVFS_WAIT_EVENT:
 579 
 580                 /* try the open again, which could trigger another retry setup
 581                    if it wants to, so we have to unmark the async flag so we
 582                    will know if it does a second async reply */
 583                 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
 584 
 585                 status = pvfs_setpathinfo(ntvfs, req, info);
 586                 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
 587                         /* the 2nd try also replied async, so we don't send
 588                            the reply yet */
 589                         return;
 590                 }
 591 
 592                 /* re-mark it async, just in case someone up the chain does
 593                    paranoid checking */
 594                 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
 595                 break;
 596         }
 597 
 598         /* send the reply up the chain */
 599         req->async_states->status = status;
 600         req->async_states->send_fn(req);
 601 }
 602 
 603 /*
 604   setup for a unlink retry after a sharing violation
 605   or a non granted oplock
 606 */
 607 static NTSTATUS pvfs_setpathinfo_setup_retry(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 608                                              struct ntvfs_request *req,
 609                                              union smb_setfileinfo *info,
 610                                              struct odb_lock *lck,
 611                                              NTSTATUS status)
 612 {
 613         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
 614                                   struct pvfs_state);
 615         struct timeval end_time;
 616 
 617         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
 618                 end_time = timeval_add(&req->statistics.request_time,
 619                                        0, pvfs->sharing_violation_delay);
 620         } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
 621                 end_time = timeval_add(&req->statistics.request_time,
 622                                        pvfs->oplock_break_timeout, 0);
 623         } else {
 624                 return NT_STATUS_INTERNAL_ERROR;
 625         }
 626 
 627         return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, info, NULL,
 628                                     pvfs_retry_setpathinfo);
 629 }
 630 
 631 /*
 632   set info on a pathname
 633 */
 634 NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 635                           struct ntvfs_request *req, union smb_setfileinfo *info)
 636 {
 637         struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
 638                                   struct pvfs_state);
 639         struct pvfs_filename *name;
 640         struct pvfs_filename newstats;
 641         NTSTATUS status;
 642         uint32_t access_needed;
 643         uint32_t change_mask = 0;
 644         struct odb_lock *lck = NULL;
 645         DATA_BLOB odb_locking_key;
 646 
 647         /* resolve the cifs name to a posix name */
 648         status = pvfs_resolve_name(pvfs, req, info->generic.in.file.path, 
 649                                    PVFS_RESOLVE_STREAMS, &name);
 650         if (!NT_STATUS_IS_OK(status)) {
 651                 return status;
 652         }
 653 
 654         if (!name->exists) {
 655                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 656         }
 657 
 658         access_needed = pvfs_setfileinfo_access(info);
 659         status = pvfs_access_check_simple(pvfs, req, name, access_needed);
 660         if (!NT_STATUS_IS_OK(status)) {
 661                 return status;
 662         }
 663 
 664         /* we take a copy of the current file stats, then update
 665            newstats in each of the elements below. At the end we
 666            compare, and make any changes needed */
 667         newstats = *name;
 668 
 669         switch (info->generic.level) {
 670         case RAW_SFILEINFO_SETATTR:
 671                 if (!null_time(info->setattr.in.write_time)) {
 672                         unix_to_nt_time(&newstats.dos.write_time, info->setattr.in.write_time);
 673                 }
 674                 if (info->setattr.in.attrib == 0) {
 675                         newstats.dos.attrib = FILE_ATTRIBUTE_NORMAL;
 676                 } else if (info->setattr.in.attrib != FILE_ATTRIBUTE_NORMAL) {
 677                         newstats.dos.attrib = info->setattr.in.attrib;
 678                 }
 679                 break;
 680 
 681         case RAW_SFILEINFO_SETATTRE:
 682         case RAW_SFILEINFO_STANDARD:
 683                 if (!null_time(info->setattre.in.create_time)) {
 684                         unix_to_nt_time(&newstats.dos.create_time, info->setattre.in.create_time);
 685                 }
 686                 if (!null_time(info->setattre.in.access_time)) {
 687                         unix_to_nt_time(&newstats.dos.access_time, info->setattre.in.access_time);
 688                 }
 689                 if (!null_time(info->setattre.in.write_time)) {
 690                         unix_to_nt_time(&newstats.dos.write_time, info->setattre.in.write_time);
 691                 }
 692                 break;
 693 
 694         case RAW_SFILEINFO_EA_SET:
 695                 return pvfs_setfileinfo_ea_set(pvfs, name, -1, 
 696                                                info->ea_set.in.num_eas,
 697                                                info->ea_set.in.eas);
 698 
 699         case RAW_SFILEINFO_BASIC_INFO:
 700         case RAW_SFILEINFO_BASIC_INFORMATION:
 701                 if (!null_nttime(info->basic_info.in.create_time)) {
 702                         newstats.dos.create_time = info->basic_info.in.create_time;
 703                 }
 704                 if (!null_nttime(info->basic_info.in.access_time)) {
 705                         newstats.dos.access_time = info->basic_info.in.access_time;
 706                 }
 707                 if (!null_nttime(info->basic_info.in.write_time)) {
 708                         newstats.dos.write_time = info->basic_info.in.write_time;
 709                 }
 710                 if (!null_nttime(info->basic_info.in.change_time)) {
 711                         newstats.dos.change_time = info->basic_info.in.change_time;
 712                 }
 713                 if (info->basic_info.in.attrib != 0) {
 714                         newstats.dos.attrib = info->basic_info.in.attrib;
 715                 }
 716                 break;
 717 
 718         case RAW_SFILEINFO_ALLOCATION_INFO:
 719         case RAW_SFILEINFO_ALLOCATION_INFORMATION:
 720                 status = pvfs_can_update_file_size(pvfs, req, name, &lck);
 721                 /*
 722                  * on a sharing violation we need to retry when the file is closed by
 723                  * the other user, or after 1 second
 724                  * on a non granted oplock we need to retry when the file is closed by
 725                  * the other user, or after 30 seconds
 726                 */
 727                 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
 728                      NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
 729                     (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
 730                         return pvfs_setpathinfo_setup_retry(pvfs->ntvfs, req, info, lck, status);
 731                 }
 732                 NT_STATUS_NOT_OK_RETURN(status);
 733 
 734                 if (info->allocation_info.in.alloc_size > newstats.dos.alloc_size) {
 735                         /* strange. Increasing the allocation size via setpathinfo 
 736                            should be silently ignored */
 737                         break;
 738                 }
 739                 newstats.dos.alloc_size = info->allocation_info.in.alloc_size;
 740                 if (newstats.dos.alloc_size < newstats.st.st_size) {
 741                         newstats.st.st_size = newstats.dos.alloc_size;
 742                 }
 743                 newstats.dos.alloc_size = pvfs_round_alloc_size(pvfs, 
 744                                                                 newstats.dos.alloc_size);
 745                 break;
 746 
 747         case RAW_SFILEINFO_END_OF_FILE_INFO:
 748         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
 749                 status = pvfs_can_update_file_size(pvfs, req, name, &lck);
 750                 /*
 751                  * on a sharing violation we need to retry when the file is closed by
 752                  * the other user, or after 1 second
 753                  * on a non granted oplock we need to retry when the file is closed by
 754                  * the other user, or after 30 seconds
 755                 */
 756                 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
 757                      NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
 758                     (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
 759                         return pvfs_setpathinfo_setup_retry(pvfs->ntvfs, req, info, lck, status);
 760                 }
 761                 NT_STATUS_NOT_OK_RETURN(status);
 762 
 763                 newstats.st.st_size = info->end_of_file_info.in.size;
 764                 break;
 765 
 766         case RAW_SFILEINFO_MODE_INFORMATION:
 767                 if (info->mode_information.in.mode != 0 &&
 768                     info->mode_information.in.mode != 2 &&
 769                     info->mode_information.in.mode != 4 &&
 770                     info->mode_information.in.mode != 6) {
 771                         return NT_STATUS_INVALID_PARAMETER;
 772                 }
 773                 return NT_STATUS_OK;
 774 
 775         case RAW_SFILEINFO_RENAME_INFORMATION:
 776         case RAW_SFILEINFO_RENAME_INFORMATION_SMB2:
 777                 status = pvfs_locking_key(name, name, &odb_locking_key);
 778                 NT_STATUS_NOT_OK_RETURN(status);
 779                 status = pvfs_setfileinfo_rename(pvfs, req, name, -1,
 780                                                  &odb_locking_key, info);
 781                 NT_STATUS_NOT_OK_RETURN(status);
 782                 return NT_STATUS_OK;
 783 
 784         case RAW_SFILEINFO_DISPOSITION_INFO:
 785         case RAW_SFILEINFO_DISPOSITION_INFORMATION:
 786         case RAW_SFILEINFO_POSITION_INFORMATION:
 787                 return NT_STATUS_OK;
 788 
 789         default:
 790                 return NT_STATUS_INVALID_LEVEL;
 791         }
 792 
 793         /* possibly change the file size */
 794         if (newstats.st.st_size != name->st.st_size) {
 795                 if (name->stream_name) {
 796                         status = pvfs_stream_truncate(pvfs, name, -1, newstats.st.st_size);
 797                         if (!NT_STATUS_IS_OK(status)) {
 798                                 return status;
 799                         }
 800                 } else if (truncate(name->full_name, newstats.st.st_size) == -1) {
 801                         return pvfs_map_errno(pvfs, errno);
 802                 }
 803                 change_mask |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
 804         }
 805 
 806         /* possibly change the file timestamps */
 807         if (newstats.dos.create_time != name->dos.create_time) {
 808                 change_mask |= FILE_NOTIFY_CHANGE_CREATION;
 809         }
 810         if (newstats.dos.access_time != name->dos.access_time) {
 811                 change_mask |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
 812         }
 813         if (newstats.dos.write_time != name->dos.write_time) {
 814                 change_mask |= FILE_NOTIFY_CHANGE_LAST_WRITE;
 815         }
 816         if ((change_mask & FILE_NOTIFY_CHANGE_LAST_ACCESS) ||
 817             (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE)) {
 818                 struct timeval tv[2];
 819 
 820                 nttime_to_timeval(&tv[0], newstats.dos.access_time);
 821                 nttime_to_timeval(&tv[1], newstats.dos.write_time);
 822 
 823                 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
 824                         if (utimes(name->full_name, tv) == -1) {
 825                                 DEBUG(0,("pvfs_setpathinfo: utimes() failed '%s' - %s\n",
 826                                          name->full_name, strerror(errno)));
 827                                 return pvfs_map_errno(pvfs, errno);
 828                         }
 829                 }
 830         }
 831         if (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE) {
 832                 if (lck == NULL) {
 833                         DATA_BLOB lkey;
 834                         status = pvfs_locking_key(name, name, &lkey);
 835                         NT_STATUS_NOT_OK_RETURN(status);
 836 
 837                         lck = odb_lock(req, pvfs->odb_context, &lkey);
 838                         data_blob_free(&lkey);
 839                         if (lck == NULL) {
 840                                 DEBUG(0,("Unable to lock opendb for write time update\n"));
 841                                 return NT_STATUS_INTERNAL_ERROR;
 842                         }
 843                 }
 844 
 845                 status = odb_set_write_time(lck, newstats.dos.write_time, true);
 846                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
 847                         /* it could be that nobody has opened the file */
 848                 } else if (!NT_STATUS_IS_OK(status)) {
 849                         DEBUG(0,("Unable to update write time: %s\n",
 850                                 nt_errstr(status)));
 851                         return status;
 852                 }
 853         }
 854 
 855         /* possibly change the attribute */
 856         newstats.dos.attrib |= (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY);
 857         if (newstats.dos.attrib != name->dos.attrib) {
 858                 mode_t mode = pvfs_fileperms(pvfs, newstats.dos.attrib);
 859                 if (chmod(name->full_name, mode) == -1) {
 860                         return pvfs_map_errno(pvfs, errno);
 861                 }
 862                 change_mask |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
 863         }
 864 
 865         *name = newstats;
 866 
 867         if (change_mask != 0) {
 868                 notify_trigger(pvfs->notify_context, 
 869                                NOTIFY_ACTION_MODIFIED, 
 870                                change_mask,
 871                                name->full_name);
 872         }
 873 
 874         return pvfs_dosattrib_save(pvfs, name, -1);
 875 }
 876 

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