コード例 #1
0
static ssize_t real_write_file(files_struct *fsp,const char *data, SMB_OFF_T pos, size_t n)
{
    ssize_t ret;

    if (pos == -1) {
        ret = vfs_write_data(fsp, data, n);
    } else {
        fsp->fh->pos = pos;
        if (pos && lp_strict_allocate(SNUM(fsp->conn))) {
            if (vfs_fill_sparse(fsp, pos) == -1) {
                return -1;
            }
        }
        ret = vfs_pwrite_data(fsp, data, n, pos);
    }

    DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n",
              fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret ));

    if (ret != -1) {
        fsp->fh->pos += ret;

        /*
         * It turns out that setting the last write time from a Windows
         * client stops any subsequent writes from updating the write time.
         * Doing this after the write gives a race condition here where
         * a stat may see the changed write time before we reset it here,
         * but it's cheaper than having to store the write time in shared
         * memory and look it up using dev/inode across all running smbd's.
         * The 99% solution will hopefully be good enough in this case. JRA.
         */

        if (fsp->pending_modtime) {
            set_filetime(fsp->conn, fsp->fsp_name, fsp->pending_modtime);

            /* If we didn't get the "set modtime" call ourselves, we must
               store the last write time to restore on close. JRA. */
            if (!fsp->pending_modtime_owner) {
                fsp->last_write_time = time(NULL);
            }
        }

        /* Yes - this is correct - writes don't update this. JRA. */
        /* Found by Samba4 tests. */
#if 0
        fsp->position_information = fsp->pos;
#endif
    }

    return ret;
}
コード例 #2
0
ファイル: fileio.c プロジェクト: Alexandr-Galko/samba
static ssize_t real_write_file(struct smb_request *req,
				files_struct *fsp,
				const char *data,
				SMB_OFF_T pos,
				size_t n)
{
	ssize_t ret;

        if (pos == -1) {
                ret = vfs_write_data(req, fsp, data, n);
        } else {
		fsp->fh->pos = pos;
		if (pos && lp_strict_allocate(SNUM(fsp->conn) &&
				!fsp->is_sparse)) {
			if (vfs_fill_sparse(fsp, pos) == -1) {
				return -1;
			}
		}
                ret = vfs_pwrite_data(req, fsp, data, n, pos);
	}

	DEBUG(10,("real_write_file (%s): pos = %.0f, size = %lu, returned %ld\n",
		  fsp_str_dbg(fsp), (double)pos, (unsigned long)n, (long)ret));

	if (ret != -1) {
		fsp->fh->pos += ret;

/* Yes - this is correct - writes don't update this. JRA. */
/* Found by Samba4 tests. */
#if 0
		fsp->position_information = fsp->pos;
#endif
	}

	return ret;
}
コード例 #3
0
int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_OFF_T len)
{
	int result = -1;
	SMB_STRUCT_STAT st;
	char c = 0;
	SMB_OFF_T currpos;

	START_PROFILE(syscall_ftruncate);

	if (lp_strict_allocate(SNUM(fsp->conn))) {
		result = strict_allocate_ftruncate(handle, fsp, fd, len);
		END_PROFILE(syscall_ftruncate);
		return result;
	}

	/* we used to just check HAVE_FTRUNCATE_EXTEND and only use
	   sys_ftruncate if the system supports it. Then I discovered that
	   you can have some filesystems that support ftruncate
	   expansion and some that don't! On Linux fat can't do
	   ftruncate extend but ext2 can. */

	result = sys_ftruncate(fd, len);
	if (result == 0)
		goto done;

	/* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
	   extend a file with ftruncate. Provide alternate implementation
	   for this */
	currpos = SMB_VFS_LSEEK(fsp, fd, 0, SEEK_CUR);
	if (currpos == -1) {
		goto done;
	}

	/* Do an fstat to see if the file is longer than the requested
	   size in which case the ftruncate above should have
	   succeeded or shorter, in which case seek to len - 1 and
	   write 1 byte of zero */
	if (SMB_VFS_FSTAT(fsp, fd, &st) == -1) {
		goto done;
	}

#ifdef S_ISFIFO
	if (S_ISFIFO(st.st_mode)) {
		result = 0;
		goto done;
	}
#endif

	if (st.st_size == len) {
		result = 0;
		goto done;
	}

	if (st.st_size > len) {
		/* the sys_ftruncate should have worked */
		goto done;
	}

	if (SMB_VFS_LSEEK(fsp, fd, len-1, SEEK_SET) != len -1)
		goto done;

	if (SMB_VFS_WRITE(fsp, fd, &c, 1)!=1)
		goto done;

	/* Seek to where we were */
	if (SMB_VFS_LSEEK(fsp, fd, currpos, SEEK_SET) != currpos)
		goto done;
	result = 0;

  done:

	END_PROFILE(syscall_ftruncate);
	return result;
}
コード例 #4
0
static NTSTATUS fsctl_zero_data(TALLOC_CTX *mem_ctx,
				struct tevent_context *ev,
				struct files_struct *fsp,
				DATA_BLOB *in_input)
{
	struct file_zero_data_info zdata_info;
	enum ndr_err_code ndr_ret;
	struct lock_struct lck;
	int mode;
	uint64_t len;
	int ret;
	NTSTATUS status;

	if (fsp == NULL) {
		return NT_STATUS_FILE_CLOSED;
	}

	/* WRITE_DATA permission is required */
	status = check_access_fsp(fsp, FILE_WRITE_DATA);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	/* allow regardless of whether FS supports sparse or not */

	ndr_ret = ndr_pull_struct_blob(in_input, mem_ctx, &zdata_info,
			(ndr_pull_flags_fn_t)ndr_pull_file_zero_data_info);
	if (ndr_ret != NDR_ERR_SUCCESS) {
		DEBUG(0, ("failed to unmarshall zero data request\n"));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (zdata_info.beyond_final_zero < zdata_info.file_off) {
		DEBUG(0, ("invalid zero data params: off %lu, bfz, %lu\n",
			  (unsigned long)zdata_info.file_off,
			  (unsigned long)zdata_info.beyond_final_zero));
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* convert strange "beyond final zero" param into length */
	len = zdata_info.beyond_final_zero - zdata_info.file_off;

	if (len == 0) {
		DEBUG(2, ("zero data called with zero length range\n"));
		return NT_STATUS_OK;
	}

	init_strict_lock_struct(fsp,
				fsp->op->global->open_persistent_id,
				zdata_info.file_off,
				len,
				WRITE_LOCK,
				&lck);

	if (!SMB_VFS_STRICT_LOCK(fsp->conn, fsp, &lck)) {
		DEBUG(2, ("failed to lock range for zero-data\n"));
		return NT_STATUS_FILE_LOCK_CONFLICT;
	}

	/*
	 * MS-FSCC <58> Section 2.3.65
	 * This FSCTL sets the range of bytes to zero (0) without extending the
	 * file size.
	 *
	 * The VFS_FALLOCATE_FL_KEEP_SIZE flag is used to satisfy this
	 * constraint.
	 */

	mode = VFS_FALLOCATE_FL_PUNCH_HOLE | VFS_FALLOCATE_FL_KEEP_SIZE;
	ret = SMB_VFS_FALLOCATE(fsp, mode, zdata_info.file_off, len);
	if (ret == -1)  {
		status = map_nt_error_from_unix_common(errno);
		DEBUG(2, ("zero-data fallocate(0x%x) failed: %s\n", mode,
		      strerror(errno)));
		SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &lck);
		return status;
	}

	if (!fsp->is_sparse && lp_strict_allocate(SNUM(fsp->conn))) {
		/*
		 * File marked non-sparse and "strict allocate" is enabled -
		 * allocate the range that we just punched out.
		 * In future FALLOC_FL_ZERO_RANGE could be used exclusively for
		 * this, but it's currently only supported on XFS and ext4.
		 *
		 * The newly allocated range still won't be found by SEEK_DATA
		 * for QAR, but stat.st_blocks will reflect it.
		 */
		ret = SMB_VFS_FALLOCATE(fsp, VFS_FALLOCATE_FL_KEEP_SIZE,
					zdata_info.file_off, len);
		if (ret == -1)  {
			status = map_nt_error_from_unix_common(errno);
			DEBUG(0, ("fallocate failed: %s\n", strerror(errno)));
			SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &lck);
			return status;
		}
	}

	SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &lck);
	return NT_STATUS_OK;
}
コード例 #5
0
ファイル: vfs.c プロジェクト: hajuuk/R7000
int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
{
	int ret;
	SMB_STRUCT_STAT st;
	connection_struct *conn = fsp->conn;
	SMB_BIG_UINT space_avail;
	SMB_BIG_UINT bsize,dfree,dsize;

	release_level_2_oplocks_on_change(fsp);

	/*
	 * Actually try and commit the space on disk....
	 */

	DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));

    /* Foxconn removed start pling 11/18/2009 */
    /* Don't check negative length, to avoid "disk full" error 
     * when copy file from Vista/Win7 to USB.
     */
#if 0
	if (((SMB_OFF_T)len) < 0) {
		DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
		errno = EINVAL;
		return -1;
	}
#endif
    /* Foxconn removed end pling 11/18/2009 */

	ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
	if (ret == -1)
		return ret;

	if (len == (SMB_BIG_UINT)st.st_size)
		return 0;

	if (len < (SMB_BIG_UINT)st.st_size) {
		/* Shrink - use ftruncate. */

		DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
				fsp->fsp_name, (double)st.st_size ));

		flush_write_cache(fsp, SIZECHANGE_FLUSH);
		if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
			set_filelen_write_cache(fsp, len);
		}
		return ret;
	}

	/* Grow - we need to test if we have enough space. */

	if (!lp_strict_allocate(SNUM(fsp->conn)))
		return 0;

	len -= st.st_size;
	len /= 1024; /* Len is now number of 1k blocks needed. */
	space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
	if (space_avail == (SMB_BIG_UINT)-1) {
		return -1;
	}

	DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
			fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));

	if (len > space_avail) {
		errno = ENOSPC;
		return -1;
	}

	return 0;
}
コード例 #6
0
int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
{
	int ret;
	SMB_STRUCT_STAT st;
	connection_struct *conn = fsp->conn;
	uint64_t space_avail;
	uint64_t bsize,dfree,dsize;

	/*
	 * Actually try and commit the space on disk....
	 */

	DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n",
		  fsp_str_dbg(fsp), (double)len));

	if (((SMB_OFF_T)len) < 0) {
		DEBUG(0,("vfs_allocate_file_space: %s negative len "
			 "requested.\n", fsp_str_dbg(fsp)));
		errno = EINVAL;
		return -1;
	}

	ret = SMB_VFS_FSTAT(fsp, &st);
	if (ret == -1)
		return ret;

	if (len == (uint64_t)st.st_ex_size)
		return 0;

	if (len < (uint64_t)st.st_ex_size) {
		/* Shrink - use ftruncate. */

		DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current "
			  "size %.0f\n", fsp_str_dbg(fsp),
			  (double)st.st_ex_size));

		contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);

		flush_write_cache(fsp, SIZECHANGE_FLUSH);
		if ((ret = SMB_VFS_FTRUNCATE(fsp, (SMB_OFF_T)len)) != -1) {
			set_filelen_write_cache(fsp, len);
		}

		contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);

		return ret;
	}

	/* Grow - we need to test if we have enough space. */

	contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW);
	contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW);

	if (!lp_strict_allocate(SNUM(fsp->conn)))
		return 0;

	len -= st.st_ex_size;
	len /= 1024; /* Len is now number of 1k blocks needed. */
	space_avail = get_dfree_info(conn, fsp->fsp_name->base_name, false,
				     &bsize, &dfree, &dsize);
	if (space_avail == (uint64_t)-1) {
		return -1;
	}

	DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, "
		  "needed blocks = %.0f, space avail = %.0f\n",
		  fsp_str_dbg(fsp), (double)st.st_ex_size, (double)len,
		  (double)space_avail));

	if (len > space_avail) {
		errno = ENOSPC;
		return -1;
	}

	return 0;
}