/* * smb_set_open_attributes * * Last write time: * - If the last_write time specified in the open params is not 0 or -1, * use it as file's mtime. This will be considered an explicitly set * timestamps, not reset by subsequent writes. * * DOS attributes * - If we created_readonly, we now store the real DOS attributes * (including the readonly bit) so subsequent opens will see it. * * Both are stored "pending" rather than in the file system. * * Returns: errno */ static int smb_set_open_attributes(smb_request_t *sr, smb_ofile_t *of) { smb_attr_t attr; smb_arg_open_t *op = &sr->sr_open; smb_node_t *node = of->f_node; int rc = 0; bzero(&attr, sizeof (smb_attr_t)); if (op->created_readonly) { attr.sa_dosattr = op->dattr | FILE_ATTRIBUTE_READONLY; attr.sa_mask |= SMB_AT_DOSATTR; } if (op->dsize != 0) { attr.sa_allocsz = op->dsize; attr.sa_mask |= SMB_AT_ALLOCSZ; } if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX)) { attr.sa_vattr.va_mtime = op->mtime; attr.sa_mask |= SMB_AT_MTIME; } /* * Used to have code here to set mtime, ctime, atime * when the open op->create_disposition is any of: * FILE_SUPERSEDE, FILE_OVERWRITE_IF, FILE_OVERWRITE. * We know that in those cases we will have set the * file size, in which case the file system will * update those times, so we don't have to. * * However, keep track of the fact that we modified * the file via this handle, so we can do the evil, * gratuitious mtime update on close that Windows * clients appear to expect. */ if (op->action_taken == SMB_OACT_TRUNCATED) of->f_written = B_TRUE; if (attr.sa_mask != 0) rc = smb_node_setattr(sr, node, of->f_cr, of, &attr); return (rc); }
/* * smb_set_open_timestamps * * Last write time: * - If the last_write time specified in the open params is not 0 or -1, * use it as file's mtime. This will be considered an explicitly set * timestamps, not reset by subsequent writes. * * Opening existing file (not directory): * - If opening an existing file for overwrite set initial ATIME, MTIME * & CTIME to now. (This is achieved by setting them as pending then forcing * an smb_node_setattr() to apply pending times.) * * - Note If opening an existing file NOT for overwrite, windows would * set the atime on file close, however setting the atime would cause * the ARCHIVE attribute to be set, which does not occur on windows, * so we do not do the atime update. * * Returns: errno */ static int smb_set_open_timestamps(smb_request_t *sr, smb_ofile_t *of, boolean_t created) { int rc = 0; smb_arg_open_t *op = &sr->sr_open; smb_node_t *node = of->f_node; boolean_t existing_file, set_times; smb_attr_t attr; bzero(&attr, sizeof (smb_attr_t)); set_times = B_FALSE; if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX)) { attr.sa_mask = SMB_AT_MTIME; attr.sa_vattr.va_mtime = op->mtime; set_times = B_TRUE; } existing_file = !(created || smb_node_is_dir(node)); if (existing_file) { switch (op->create_disposition) { case FILE_SUPERSEDE: case FILE_OVERWRITE_IF: case FILE_OVERWRITE: smb_ofile_set_write_time_pending(of); set_times = B_TRUE; break; default: break; } } if (set_times) rc = smb_node_setattr(sr, node, sr->user_cr, of, &attr); return (rc); }
/* * smb_ofile_close */ void smb_ofile_close(smb_ofile_t *of, int32_t mtime_sec) { timestruc_t now; uint32_t flags = 0; SMB_OFILE_VALID(of); mutex_enter(&of->f_mutex); ASSERT(of->f_refcnt); switch (of->f_state) { case SMB_OFILE_STATE_OPEN: { of->f_state = SMB_OFILE_STATE_CLOSING; mutex_exit(&of->f_mutex); if (of->f_ftype == SMB_FTYPE_MESG_PIPE) { smb_opipe_close(of); smb_server_dec_pipes(of->f_server); } else { smb_attr_t *pa = &of->f_pending_attr; /* * In here we make changes to of->f_pending_attr * while not holding of->f_mutex. This is OK * because we've changed f_state to CLOSING, * so no more threads will take this path. */ if (mtime_sec != 0) { pa->sa_vattr.va_mtime.tv_sec = mtime_sec; pa->sa_mask |= SMB_AT_MTIME; } /* * If we have ever modified data via this handle * (write or truncate) and if the mtime was not * set via this handle, update the mtime again * during the close. Windows expects this. * [ MS-FSA 2.1.5.4 "Update Timestamps" ] */ if (of->f_written && (pa->sa_mask & SMB_AT_MTIME) == 0) { pa->sa_mask |= SMB_AT_MTIME; gethrestime(&now); pa->sa_vattr.va_mtime = now; } if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE) { if (smb_tree_has_feature(of->f_tree, SMB_TREE_CATIA)) { flags |= SMB_CATIA; } (void) smb_node_set_delete_on_close(of->f_node, of->f_cr, flags); } smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid); smb_node_destroy_lock_by_ofile(of->f_node, of); if (smb_node_is_file(of->f_node)) { (void) smb_fsop_close(of->f_node, of->f_mode, of->f_cr); smb_oplock_release(of->f_node, of); } if (smb_node_dec_open_ofiles(of->f_node) == 0) { /* * Last close. The f_pending_attr has * only times (atime,ctime,mtime) so * we can borrow it to commit the * n_pending_dosattr from the node. */ pa->sa_dosattr = of->f_node->n_pending_dosattr; if (pa->sa_dosattr != 0) pa->sa_mask |= SMB_AT_DOSATTR; /* Let's leave this zero when not in use. */ of->f_node->n_allocsz = 0; } if (pa->sa_mask != 0) { /* * Commit any pending attributes from * the ofile we're closing. Note that * we pass NULL as the ofile to setattr * so it will write to the file system * and not keep anything on the ofile. * This clears n_pending_dosattr if * there are no opens, otherwise the * dosattr will be pending again. */ (void) smb_node_setattr(NULL, of->f_node, of->f_cr, NULL, pa); } /* * Cancel any notify change requests that * may be using this open instance. */ if (of->f_node->n_fcn.fcn_count) smb_notify_file_closed(of); smb_server_dec_files(of->f_server); } atomic_dec_32(&of->f_tree->t_open_files); mutex_enter(&of->f_mutex); ASSERT(of->f_refcnt); ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING); of->f_state = SMB_OFILE_STATE_CLOSED; break; } case SMB_OFILE_STATE_CLOSED: case SMB_OFILE_STATE_CLOSING: break; default: ASSERT(0); break; } mutex_exit(&of->f_mutex); }