Esempio n. 1
0
NTSTATUS set_create_timespec_ea(connection_struct *conn,
				const struct smb_filename *psmb_fname,
				struct timespec create_time)
{
	struct smb_filename *smb_fname;
	uint32_t dosmode;
	int ret;

	if (!lp_store_dos_attributes(SNUM(conn))) {
		return NT_STATUS_OK;
	}

	smb_fname = synthetic_smb_fname(talloc_tos(), psmb_fname->base_name,
					NULL, &psmb_fname->st);

	if (smb_fname == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	dosmode = dos_mode(conn, smb_fname);

	smb_fname->st.st_ex_btime = create_time;

	ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
	if (ret == -1) {
		map_nt_error_from_unix(errno);
	}

	DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
		smb_fname_str_dbg(smb_fname)));

	return NT_STATUS_OK;
}
Esempio n. 2
0
void mark_file_modified(files_struct *fsp)
{
	int dosmode;

	if (fsp->modified) {
		return;
	}

	fsp->modified = true;

	if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
		return;
	}
	trigger_write_time_update(fsp);

	if (fsp->posix_open) {
		return;
	}
	if (!(lp_store_dos_attributes(SNUM(fsp->conn)) ||
	      MAP_ARCHIVE(fsp->conn))) {
		return;
	}

	dosmode = dos_mode(fsp->conn, fsp->fsp_name);
	if (IS_DOS_ARCHIVE(dosmode)) {
		return;
	}
	file_set_dosmode(fsp->conn, fsp->fsp_name,
			 dosmode | FILE_ATTRIBUTE_ARCHIVE, NULL, false);
}
Esempio n. 3
0
/*******************************************************************
chmod a file - but preserve some bits
********************************************************************/
int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *st)
{
  SMB_STRUCT_STAT st1;
  int mask=0;
  mode_t tmp;
  mode_t unixmode;

  if (!st) {
    st = &st1;
    if (dos_stat(fname,st)) return(-1);
  }

  if (S_ISDIR(st->st_mode)) dosmode |= aDIR;

  if (dos_mode(conn,fname,st) == dosmode) return(0);

  unixmode = unix_mode(conn,dosmode,fname);

  /* preserve the s bits */
  mask |= (S_ISUID | S_ISGID);

  /* preserve the t bit */
#ifdef S_ISVTX
  mask |= S_ISVTX;
#endif

  /* possibly preserve the x bits */
  if (!MAP_ARCHIVE(conn)) mask |= S_IXUSR;
  if (!MAP_SYSTEM(conn)) mask |= S_IXGRP;
  if (!MAP_HIDDEN(conn)) mask |= S_IXOTH;

  unixmode |= (st->st_mode & mask);

  /* if we previously had any r bits set then leave them alone */
  if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
    unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
    unixmode |= tmp;
  }

  /* if we previously had any w bits set then leave them alone 
   whilst adding in the new w bits, if the new mode is not rdonly */
  if (!IS_DOS_READONLY(dosmode)) {
    unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
  }

  return(dos_chmod(fname,unixmode));
}
Esempio n. 4
0
static void setup_close_full_information(connection_struct *conn,
				struct smb_filename *smb_fname,
				bool posix_open,
				struct timespec *out_creation_ts,
				struct timespec *out_last_access_ts,
				struct timespec *out_last_write_ts,
				struct timespec *out_change_ts,
				uint16_t *out_flags,
				uint64_t *out_allocation_size,
				uint64_t *out_end_of_file,
				uint32_t *out_file_attributes)
{
	int ret;
	if (posix_open) {
		ret = SMB_VFS_LSTAT(conn, smb_fname);
	} else {
		ret = SMB_VFS_STAT(conn, smb_fname);
	}
	if (ret != 0) {
		return;
	}

	*out_flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
	*out_file_attributes = dos_mode(conn, smb_fname);
	*out_last_write_ts = smb_fname->st.st_ex_mtime;
	*out_last_access_ts = smb_fname->st.st_ex_atime;
	*out_creation_ts = get_create_timespec(conn, NULL, smb_fname);
	*out_change_ts = get_change_timespec(conn, NULL, smb_fname);

	if (lp_dos_filetime_resolution(SNUM(conn))) {
		dos_filetime_timespec(out_creation_ts);
		dos_filetime_timespec(out_last_write_ts);
		dos_filetime_timespec(out_last_access_ts);
		dos_filetime_timespec(out_change_ts);
	}
	if (!(*out_file_attributes & FILE_ATTRIBUTE_DIRECTORY)) {
		*out_end_of_file = get_file_size_stat(&smb_fname->st);
	}

	*out_allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
}
Esempio n. 5
0
NTSTATUS file_set_sparse(connection_struct *conn,
			 files_struct *fsp,
			 bool sparse)
{
	uint32_t old_dosmode;
	uint32_t new_dosmode;
	NTSTATUS status;

	if (!CAN_WRITE(conn)) {
		DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
			"on readonly share[%s]\n",
			smb_fname_str_dbg(fsp->fsp_name),
			sparse,
			lp_servicename(talloc_tos(), SNUM(conn))));
		return NT_STATUS_MEDIA_WRITE_PROTECTED;
	}

	/*
	 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
	 * following access flags are granted.
	 */
	if ((fsp->access_mask & (FILE_WRITE_DATA
				| FILE_WRITE_ATTRIBUTES
				| SEC_FILE_APPEND_DATA)) == 0) {
		DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
			"access_mask[0x%08X] - access denied\n",
			smb_fname_str_dbg(fsp->fsp_name),
			sparse,
			fsp->access_mask));
		return NT_STATUS_ACCESS_DENIED;
	}

	if (fsp->is_directory) {
		DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
			  (sparse ? "set" : "clear"),
			  smb_fname_str_dbg(fsp->fsp_name)));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (IS_IPC(conn) || IS_PRINT(conn)) {
		DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
			  (sparse ? "set" : "clear")));
		return NT_STATUS_INVALID_PARAMETER;
	}

	DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
		  sparse, smb_fname_str_dbg(fsp->fsp_name)));

	if (!lp_store_dos_attributes(SNUM(conn))) {
		return NT_STATUS_INVALID_DEVICE_REQUEST;
	}

	status = vfs_stat_fsp(fsp);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	old_dosmode = dos_mode(conn, fsp->fsp_name);

	if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
		new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
	} else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
		new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
	} else {
		return NT_STATUS_OK;
	}

	/* Store the DOS attributes in an EA. */
	if (!set_ea_dos_attribute(conn, fsp->fsp_name,
				  new_dosmode)) {
		if (errno == 0) {
			errno = EIO;
		}
		return map_nt_error_from_unix(errno);
	}

	notify_fname(conn, NOTIFY_ACTION_MODIFIED,
		     FILE_NOTIFY_CHANGE_ATTRIBUTES,
		     fsp->fsp_name->base_name);

	fsp->is_sparse = sparse;

	return NT_STATUS_OK;
}
Esempio n. 6
0
int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
		     uint32 dosmode, const char *parent_dir, bool newfile)
{
	int mask=0;
	mode_t tmp;
	mode_t unixmode;
	int ret = -1, lret = -1;
	uint32_t old_mode;
	struct timespec new_create_timespec;
	files_struct *fsp = NULL;
	bool need_close = false;
	NTSTATUS status;

	if (!CAN_WRITE(conn)) {
		errno = EROFS;
		return -1;
	}

	/* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
	dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);

	DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
		  dosmode, smb_fname_str_dbg(smb_fname)));

	unixmode = smb_fname->st.st_ex_mode;

	get_acl_group_bits(conn, smb_fname->base_name,
			   &smb_fname->st.st_ex_mode);

	if (S_ISDIR(smb_fname->st.st_ex_mode))
		dosmode |= FILE_ATTRIBUTE_DIRECTORY;
	else
		dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;

	new_create_timespec = smb_fname->st.st_ex_btime;

	old_mode = dos_mode(conn, smb_fname);

	if ((dosmode & FILE_ATTRIBUTE_OFFLINE) &&
	    !(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
		lret = SMB_VFS_SET_OFFLINE(conn, smb_fname);
		if (lret == -1) {
			if (errno == ENOTSUP) {
				DEBUG(10, ("Setting FILE_ATTRIBUTE_OFFLINE for "
					   "%s/%s is not supported.\n",
					   parent_dir,
					   smb_fname_str_dbg(smb_fname)));
			} else {
				DEBUG(0, ("An error occurred while setting "
					  "FILE_ATTRIBUTE_OFFLINE for "
					  "%s/%s: %s", parent_dir,
					  smb_fname_str_dbg(smb_fname),
					  strerror(errno)));
			}
		}
	}

	dosmode  &= ~FILE_ATTRIBUTE_OFFLINE;
	old_mode &= ~FILE_ATTRIBUTE_OFFLINE;

	smb_fname->st.st_ex_btime = new_create_timespec;

	/* Store the DOS attributes in an EA by preference. */
	if (lp_store_dos_attributes(SNUM(conn))) {
		/*
		 * Don't fall back to using UNIX modes. Finally
		 * follow the smb.conf manpage.
		 */
		if (!set_ea_dos_attribute(conn, smb_fname, dosmode)) {
			return -1;
		}
		if (!newfile) {
			notify_fname(conn, NOTIFY_ACTION_MODIFIED,
				     FILE_NOTIFY_CHANGE_ATTRIBUTES,
				     smb_fname->base_name);
		}
		smb_fname->st.st_ex_mode = unixmode;
		return 0;
	}

	unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);

	/* preserve the file type bits */
	mask |= S_IFMT;

	/* preserve the s bits */
	mask |= (S_ISUID | S_ISGID);

	/* preserve the t bit */
#ifdef S_ISVTX
	mask |= S_ISVTX;
#endif

	/* possibly preserve the x bits */
	if (!MAP_ARCHIVE(conn))
		mask |= S_IXUSR;
	if (!MAP_SYSTEM(conn))
		mask |= S_IXGRP;
	if (!MAP_HIDDEN(conn))
		mask |= S_IXOTH;

	unixmode |= (smb_fname->st.st_ex_mode & mask);

	/* if we previously had any r bits set then leave them alone */
	if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
		unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
		unixmode |= tmp;
	}

	/* if we previously had any w bits set then leave them alone 
		whilst adding in the new w bits, if the new mode is not rdonly */
	if (!IS_DOS_READONLY(dosmode)) {
		unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
	}

	/*
	 * From the chmod 2 man page:
	 *
	 * "If the calling process is not privileged, and the group of the file
	 * does not match the effective group ID of the process or one of its
	 * supplementary group IDs, the S_ISGID bit will be turned off, but
	 * this will not cause an error to be returned."
	 *
	 * Simply refuse to do the chmod in this case.
	 */

	if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
			geteuid() != sec_initial_uid() &&
			!current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
		DEBUG(3,("file_set_dosmode: setgid bit cannot be "
			"set for directory %s\n",
			smb_fname_str_dbg(smb_fname)));
		errno = EPERM;
		return -1;
	}

	ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
	if (ret == 0) {
		if(!newfile || (lret != -1)) {
			notify_fname(conn, NOTIFY_ACTION_MODIFIED,
				     FILE_NOTIFY_CHANGE_ATTRIBUTES,
				     smb_fname->base_name);
		}
		smb_fname->st.st_ex_mode = unixmode;
		return 0;
	}

	if((errno != EPERM) && (errno != EACCES))
		return -1;

	if(!lp_dos_filemode(SNUM(conn)))
		return -1;

	/* We want DOS semantics, ie allow non owner with write permission to change the
		bits on a file. Just like file_ntimes below.
	*/

	if (!can_write_to_file(conn, smb_fname)) {
		errno = EACCES;
		return -1;
	}

	/*
	 * We need to get an open file handle to do the
	 * metadata operation under root.
	 */

	status = get_file_handle_for_metadata(conn,
					      smb_fname,
					      &fsp,
					      &need_close);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		return -1;
	}

	become_root();
	ret = SMB_VFS_FCHMOD(fsp, unixmode);
	unbecome_root();
	if (need_close) {
		close_file(NULL, fsp, NORMAL_CLOSE);
	}
	if (!newfile) {
		notify_fname(conn, NOTIFY_ACTION_MODIFIED,
			     FILE_NOTIFY_CHANGE_ATTRIBUTES,
			     smb_fname->base_name);
	}
	if (ret == 0) {
		smb_fname->st.st_ex_mode = unixmode;
	}

	return( ret );
}
Esempio n. 7
0
ssize_t write_file(struct smb_request *req,
			files_struct *fsp,
			const char *data,
			SMB_OFF_T pos,
			size_t n)
{
	write_cache *wcp = fsp->wcp;
	ssize_t total_written = 0;
	int write_path = -1;

	if (fsp->print_file) {
		uint32_t t;
		int ret;

		ret = print_spool_write(fsp, data, n, pos, &t);
		if (ret) {
			errno = ret;
			return -1;
		}
		return t;
	}

	if (!fsp->can_write) {
		errno = EPERM;
		return -1;
	}

	if (!fsp->modified) {
		fsp->modified = True;

		if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) == 0) {
			trigger_write_time_update(fsp);
			if (!fsp->posix_open &&
					(lp_store_dos_attributes(SNUM(fsp->conn)) ||
					MAP_ARCHIVE(fsp->conn))) {
				int dosmode = dos_mode(fsp->conn, fsp->fsp_name);
				if (!IS_DOS_ARCHIVE(dosmode)) {
					file_set_dosmode(fsp->conn, fsp->fsp_name,
						 dosmode | FILE_ATTRIBUTE_ARCHIVE, NULL, false);
				}
			}

			/*
			 * If this is the first write and we have an exclusive oplock then setup
			 * the write cache.
			 */

			if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
				setup_write_cache(fsp,
						 fsp->fsp_name->st.st_ex_size);
				wcp = fsp->wcp;
			}
		}
	}

#ifdef WITH_PROFILE
	DO_PROFILE_INC(writecache_total_writes);
	if (!fsp->oplock_type) {
		DO_PROFILE_INC(writecache_non_oplock_writes);
	}
#endif

	/*
	 * If this file is level II oplocked then we need
	 * to grab the shared memory lock and inform all
	 * other files with a level II lock that they need
	 * to flush their read caches. We keep the lock over
	 * the shared memory area whilst doing this.
	 */

	/* This should actually be improved to span the write. */
	contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
	contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);

#ifdef WITH_PROFILE
	if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
		DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
			profile_p->writecache_init_writes,
			profile_p->writecache_abutted_writes,
			profile_p->writecache_total_writes,
			profile_p->writecache_non_oplock_writes,
			profile_p->writecache_allocated_write_caches,
			profile_p->writecache_num_write_caches,
			profile_p->writecache_direct_writes,
			profile_p->writecache_num_perfect_writes,
			profile_p->writecache_read_hits ));

		DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
			profile_p->writecache_flushed_writes[SEEK_FLUSH],
			profile_p->writecache_flushed_writes[READ_FLUSH],
			profile_p->writecache_flushed_writes[WRITE_FLUSH],
			profile_p->writecache_flushed_writes[READRAW_FLUSH],
			profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
			profile_p->writecache_flushed_writes[CLOSE_FLUSH],
			profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
	}
Esempio n. 8
0
int file_set_dosmode(connection_struct *conn, const char *fname,
		     uint32 dosmode, SMB_STRUCT_STAT *st,
		     const char *parent_dir)
{
	SMB_STRUCT_STAT st1;
	int mask=0;
	mode_t tmp;
	mode_t unixmode;
	int ret = -1;

	/* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
	dosmode &= SAMBA_ATTRIBUTES_MASK;

	DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));

	if (st == NULL) {
		SET_STAT_INVALID(st1);
		st = &st1;
	}

	if (!VALID_STAT(*st)) {
		if (SMB_VFS_STAT(conn,fname,st))
			return(-1);
	}

	unixmode = st->st_mode;

	get_acl_group_bits(conn, fname, &st->st_mode);

	if (S_ISDIR(st->st_mode))
		dosmode |= aDIR;
	else
		dosmode &= ~aDIR;

	if (dos_mode(conn,fname,st) == dosmode) {
		st->st_mode = unixmode;
		return(0);
	}

	/* Store the DOS attributes in an EA by preference. */
	if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
		st->st_mode = unixmode;
		return 0;
	}

	unixmode = unix_mode(conn,dosmode,fname, parent_dir);

	/* preserve the s bits */
	mask |= (S_ISUID | S_ISGID);

	/* preserve the t bit */
#ifdef S_ISVTX
	mask |= S_ISVTX;
#endif

	/* possibly preserve the x bits */
	if (!MAP_ARCHIVE(conn))
		mask |= S_IXUSR;
	if (!MAP_SYSTEM(conn))
		mask |= S_IXGRP;
	if (!MAP_HIDDEN(conn))
		mask |= S_IXOTH;

	unixmode |= (st->st_mode & mask);

	/* if we previously had any r bits set then leave them alone */
	if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
		unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
		unixmode |= tmp;
	}

	/* if we previously had any w bits set then leave them alone 
		whilst adding in the new w bits, if the new mode is not rdonly */
	if (!IS_DOS_READONLY(dosmode)) {
		unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
	}

	if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0) {
		notify_fname(conn, NOTIFY_ACTION_MODIFIED,
			     FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
		st->st_mode = unixmode;
		return 0;
	}

	if((errno != EPERM) && (errno != EACCES))
		return -1;

	if(!lp_dos_filemode(SNUM(conn)))
		return -1;

	/* We want DOS semantics, ie allow non owner with write permission to change the
		bits on a file. Just like file_ntimes below.
	*/

	/* Check if we have write access. */
	if (CAN_WRITE(conn)) {
		/*
		 * We need to open the file with write access whilst
		 * still in our current user context. This ensures we
		 * are not violating security in doing the fchmod.
		 * This file open does *not* break any oplocks we are
		 * holding. We need to review this.... may need to
		 * break batch oplocks open by others. JRA.
		 */
		files_struct *fsp;
		if (!NT_STATUS_IS_OK(open_file_fchmod(conn,fname,st,&fsp)))
			return -1;
		become_root();
		ret = SMB_VFS_FCHMOD(fsp, fsp->fh->fd, unixmode);
		unbecome_root();
		close_file_fchmod(fsp);
		notify_fname(conn, NOTIFY_ACTION_MODIFIED,
			     FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
		if (ret == 0) {
			st->st_mode = unixmode;
		}
	}

	return( ret );
}
Esempio n. 9
0
ssize_t write_file(files_struct *fsp, const char *data, SMB_OFF_T pos, size_t n)
{
    write_cache *wcp = fsp->wcp;
    ssize_t total_written = 0;
    int write_path = -1;

    if (fsp->print_file) {
#ifdef AVM_NO_PRINTING
        errno = EBADF;
        return -1;
#else
        fstring sharename;
        uint32 jobid;

        if (!rap_to_pjobid(fsp->rap_print_jobid, sharename, &jobid)) {
            DEBUG(3,("write_file: Unable to map RAP jobid %u to jobid.\n",
                     (unsigned int)fsp->rap_print_jobid ));
            errno = EBADF;
            return -1;
        }

        return print_job_write(SNUM(fsp->conn), jobid, data, pos, n);
#endif /* AVM_NO_PRINTING */
    }

    if (!fsp->can_write) {
        errno = EPERM;
        return(0);
    }

    if (!fsp->modified) {
        SMB_STRUCT_STAT st;
        fsp->modified = True;

        if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) {
            int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
            if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) {
                file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st, False);
            }

            /*
             * If this is the first write and we have an exclusive oplock then setup
             * the write cache.
             */

            if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
                setup_write_cache(fsp, st.st_size);
                wcp = fsp->wcp;
            }
        }
    }

#ifdef WITH_PROFILE
    DO_PROFILE_INC(writecache_total_writes);
    if (!fsp->oplock_type) {
        DO_PROFILE_INC(writecache_non_oplock_writes);
    }
#endif

    /*
     * If this file is level II oplocked then we need
     * to grab the shared memory lock and inform all
     * other files with a level II lock that they need
     * to flush their read caches. We keep the lock over
     * the shared memory area whilst doing this.
     */

    release_level_2_oplocks_on_change(fsp);

#ifdef WITH_PROFILE
    if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
        DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
                 profile_p->writecache_init_writes,
                 profile_p->writecache_abutted_writes,
                 profile_p->writecache_total_writes,
                 profile_p->writecache_non_oplock_writes,
                 profile_p->writecache_allocated_write_caches,
                 profile_p->writecache_num_write_caches,
                 profile_p->writecache_direct_writes,
                 profile_p->writecache_num_perfect_writes,
                 profile_p->writecache_read_hits ));

        DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
                 profile_p->writecache_flushed_writes[SEEK_FLUSH],
                 profile_p->writecache_flushed_writes[READ_FLUSH],
                 profile_p->writecache_flushed_writes[WRITE_FLUSH],
                 profile_p->writecache_flushed_writes[READRAW_FLUSH],
                 profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
                 profile_p->writecache_flushed_writes[CLOSE_FLUSH],
                 profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
    }
Esempio n. 10
0
static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req,
				struct files_struct *fsp,
				uint16_t in_flags,
				DATA_BLOB *outbody)
{
	NTSTATUS status;
	struct smb_request *smbreq;
	connection_struct *conn = req->tcon->compat_conn;
	struct smb_filename *smb_fname = NULL;
	struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts;
	uint64_t allocation_size = 0;
	uint64_t file_size = 0;
	uint32_t dos_attrs = 0;
	uint16_t out_flags = 0;
	bool posix_open = false;

	ZERO_STRUCT(create_date_ts);
	ZERO_STRUCT(adate_ts);
	ZERO_STRUCT(mdate_ts);
	ZERO_STRUCT(cdate_ts);

	DEBUG(10,("smbd_smb2_close: %s - fnum[%d]\n",
		  fsp_str_dbg(fsp), fsp->fnum));

	smbreq = smbd_smb2_fake_smb_request(req);
	if (smbreq == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	posix_open = fsp->posix_open;
	status = copy_smb_filename(talloc_tos(),
				fsp->fsp_name,
				&smb_fname);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	status = close_file(smbreq, fsp, NORMAL_CLOSE);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(5,("smbd_smb2_close: close_file[%s]: %s\n",
			 fsp_str_dbg(fsp), nt_errstr(status)));
		return status;
	}

	if (in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
		int ret;
		if (posix_open) {
			ret = SMB_VFS_LSTAT(conn, smb_fname);
		} else {
			ret = SMB_VFS_STAT(conn, smb_fname);
		}
		if (ret == 0) {
			out_flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
			dos_attrs = dos_mode(conn, smb_fname);
			mdate_ts = smb_fname->st.st_ex_mtime;
			adate_ts = smb_fname->st.st_ex_atime;
			create_date_ts = get_create_timespec(conn, NULL, smb_fname);
			cdate_ts = get_change_timespec(conn, NULL, smb_fname);

			if (lp_dos_filetime_resolution(SNUM(conn))) {
				dos_filetime_timespec(&create_date_ts);
				dos_filetime_timespec(&mdate_ts);
				dos_filetime_timespec(&adate_ts);
				dos_filetime_timespec(&cdate_ts);
			}
			if (!(dos_attrs & FILE_ATTRIBUTE_DIRECTORY)) {
				file_size = get_file_size_stat(&smb_fname->st);
			}

			allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
		}
	}

	SSVAL(outbody->data, 0x00, 0x3C);	/* struct size */
	SSVAL(outbody->data, 0x02, out_flags);	/* flags */
	SIVAL(outbody->data, 0x04, 0);		/* reserved */
	put_long_date_timespec(conn->ts_res,
		(char *)&outbody->data[0x8],create_date_ts); /* creation time */
	put_long_date_timespec(conn->ts_res,
		(char *)&outbody->data[0x10],adate_ts); /* last access time */
	put_long_date_timespec(conn->ts_res,
		(char *)&outbody->data[0x18],mdate_ts); /* last write time */
	put_long_date_timespec(conn->ts_res,
		(char *)&outbody->data[0x20],cdate_ts); /* change time */
	SBVAL(outbody->data, 0x28, allocation_size);/* allocation size */
	SBVAL(outbody->data, 0x30, file_size);	/* end of file */
	SIVAL(outbody->data, 0x38, dos_attrs);	/* file attributes */

	return NT_STATUS_OK;
}
Esempio n. 11
0
static NTSTATUS smbd_smb2_close(struct smbd_smb2_request *req,
				struct files_struct *fsp,
				uint16_t in_flags,
				uint16_t *out_flags,
				struct timespec *out_creation_ts,
				struct timespec *out_last_access_ts,
				struct timespec *out_last_write_ts,
				struct timespec *out_change_ts,
				uint64_t *out_allocation_size,
				uint64_t *out_end_of_file,
				uint32_t *out_file_attributes)
{
	NTSTATUS status;
	struct smb_request *smbreq;
	connection_struct *conn = req->tcon->compat;
	struct smb_filename *smb_fname = NULL;
	uint64_t allocation_size = 0;
	uint64_t file_size = 0;
	uint32_t dos_attrs = 0;
	uint16_t flags = 0;
	bool posix_open = false;

	ZERO_STRUCTP(out_creation_ts);
	ZERO_STRUCTP(out_last_access_ts);
	ZERO_STRUCTP(out_last_write_ts);
	ZERO_STRUCTP(out_change_ts);

	*out_flags = 0;
	*out_allocation_size = 0;
	*out_end_of_file = 0;
	*out_file_attributes = 0;

	DEBUG(10,("smbd_smb2_close: %s - %s\n",
		  fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));

	smbreq = smbd_smb2_fake_smb_request(req);
	if (smbreq == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	posix_open = fsp->posix_open;
	smb_fname = cp_smb_filename(talloc_tos(), fsp->fsp_name);
	if (smb_fname == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	status = close_file(smbreq, fsp, NORMAL_CLOSE);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(5,("smbd_smb2_close: close_file[%s]: %s\n",
			 fsp_str_dbg(fsp), nt_errstr(status)));
		return status;
	}

	if (in_flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
		int ret;
		if (posix_open) {
			ret = SMB_VFS_LSTAT(conn, smb_fname);
		} else {
			ret = SMB_VFS_STAT(conn, smb_fname);
		}
		if (ret == 0) {
			flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
			dos_attrs = dos_mode(conn, smb_fname);
			*out_last_write_ts = smb_fname->st.st_ex_mtime;
			*out_last_access_ts = smb_fname->st.st_ex_atime;
			*out_creation_ts = get_create_timespec(conn, NULL, smb_fname);
			*out_change_ts = get_change_timespec(conn, NULL, smb_fname);

			if (lp_dos_filetime_resolution(SNUM(conn))) {
				dos_filetime_timespec(out_creation_ts);
				dos_filetime_timespec(out_last_write_ts);
				dos_filetime_timespec(out_last_access_ts);
				dos_filetime_timespec(out_change_ts);
			}
			if (!(dos_attrs & FILE_ATTRIBUTE_DIRECTORY)) {
				file_size = get_file_size_stat(&smb_fname->st);
			}

			allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
		}
	}

	*out_flags = flags;
	*out_allocation_size = allocation_size;
	*out_end_of_file = file_size;
	*out_file_attributes = dos_attrs;

	return NT_STATUS_OK;
}