Browse Source

pre-upload action: add file open flags

Reading the flags the hook receiver can detect if the client wants to
truncate the target file
Nicola Murino 4 years ago
parent
commit
c1239fbf59
10 changed files with 33 additions and 26 deletions
  1. 7 3
      common/actions.go
  2. 10 9
      common/actions_test.go
  3. 1 1
      common/connection.go
  4. 2 0
      docs/custom-actions.md
  5. 3 3
      ftpd/handler.go
  6. 1 1
      httpd/handler.go
  7. 4 4
      sftpd/handler.go
  8. 2 2
      sftpd/scp.go
  9. 1 1
      webdavd/file.go
  10. 2 2
      webdavd/handler.go

+ 7 - 3
common/actions.go

@@ -50,7 +50,7 @@ func InitializeActionHandler(handler ActionHandler) {
 }
 }
 
 
 // ExecutePreAction executes a pre-* action and returns the result
 // ExecutePreAction executes a pre-* action and returns the result
-func ExecutePreAction(user *dataprovider.User, operation, filePath, virtualPath, protocol string, fileSize int64) error {
+func ExecutePreAction(user *dataprovider.User, operation, filePath, virtualPath, protocol string, fileSize int64, openFlags int) error {
 	if !utils.IsStringInSlice(operation, Config.Actions.ExecuteOn) {
 	if !utils.IsStringInSlice(operation, Config.Actions.ExecuteOn) {
 		// for pre-delete we execute the internal handling on error, so we must return errUnconfiguredAction.
 		// for pre-delete we execute the internal handling on error, so we must return errUnconfiguredAction.
 		// Other pre action will deny the operation on error so if we have no configuration we must return
 		// Other pre action will deny the operation on error so if we have no configuration we must return
@@ -60,13 +60,13 @@ func ExecutePreAction(user *dataprovider.User, operation, filePath, virtualPath,
 		}
 		}
 		return nil
 		return nil
 	}
 	}
-	notification := newActionNotification(user, operation, filePath, virtualPath, "", "", protocol, fileSize, nil)
+	notification := newActionNotification(user, operation, filePath, virtualPath, "", "", protocol, fileSize, openFlags, nil)
 	return actionHandler.Handle(notification)
 	return actionHandler.Handle(notification)
 }
 }
 
 
 // ExecuteActionNotification executes the defined hook, if any, for the specified action
 // ExecuteActionNotification executes the defined hook, if any, for the specified action
 func ExecuteActionNotification(user *dataprovider.User, operation, filePath, virtualPath, target, sshCmd, protocol string, fileSize int64, err error) {
 func ExecuteActionNotification(user *dataprovider.User, operation, filePath, virtualPath, target, sshCmd, protocol string, fileSize int64, err error) {
-	notification := newActionNotification(user, operation, filePath, virtualPath, target, sshCmd, protocol, fileSize, err)
+	notification := newActionNotification(user, operation, filePath, virtualPath, target, sshCmd, protocol, fileSize, 0, err)
 
 
 	if utils.IsStringInSlice(operation, Config.Actions.ExecuteSync) {
 	if utils.IsStringInSlice(operation, Config.Actions.ExecuteSync) {
 		actionHandler.Handle(notification) //nolint:errcheck
 		actionHandler.Handle(notification) //nolint:errcheck
@@ -94,12 +94,14 @@ type ActionNotification struct {
 	Endpoint   string `json:"endpoint,omitempty"`
 	Endpoint   string `json:"endpoint,omitempty"`
 	Status     int    `json:"status"`
 	Status     int    `json:"status"`
 	Protocol   string `json:"protocol"`
 	Protocol   string `json:"protocol"`
+	OpenFlags  int    `json:"open_flags,omitempty"`
 }
 }
 
 
 func newActionNotification(
 func newActionNotification(
 	user *dataprovider.User,
 	user *dataprovider.User,
 	operation, filePath, virtualPath, target, sshCmd, protocol string,
 	operation, filePath, virtualPath, target, sshCmd, protocol string,
 	fileSize int64,
 	fileSize int64,
+	openFlags int,
 	err error,
 	err error,
 ) *ActionNotification {
 ) *ActionNotification {
 	var bucket, endpoint string
 	var bucket, endpoint string
@@ -142,6 +144,7 @@ func newActionNotification(
 		Endpoint:   endpoint,
 		Endpoint:   endpoint,
 		Status:     status,
 		Status:     status,
 		Protocol:   protocol,
 		Protocol:   protocol,
+		OpenFlags:  openFlags,
 	}
 	}
 }
 }
 
 
@@ -230,5 +233,6 @@ func notificationAsEnvVars(notification *ActionNotification) []string {
 		fmt.Sprintf("SFTPGO_ACTION_ENDPOINT=%v", notification.Endpoint),
 		fmt.Sprintf("SFTPGO_ACTION_ENDPOINT=%v", notification.Endpoint),
 		fmt.Sprintf("SFTPGO_ACTION_STATUS=%v", notification.Status),
 		fmt.Sprintf("SFTPGO_ACTION_STATUS=%v", notification.Status),
 		fmt.Sprintf("SFTPGO_ACTION_PROTOCOL=%v", notification.Protocol),
 		fmt.Sprintf("SFTPGO_ACTION_PROTOCOL=%v", notification.Protocol),
+		fmt.Sprintf("SFTPGO_ACTION_OPEN_FLAGS=%v", notification.OpenFlags),
 	}
 	}
 }
 }

+ 10 - 9
common/actions_test.go

@@ -35,38 +35,39 @@ func TestNewActionNotification(t *testing.T) {
 	user.FsConfig.SFTPConfig = vfs.SFTPFsConfig{
 	user.FsConfig.SFTPConfig = vfs.SFTPFsConfig{
 		Endpoint: "sftpendpoint",
 		Endpoint: "sftpendpoint",
 	}
 	}
-	a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSFTP, 123, errors.New("fake error"))
+	a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSFTP, 123, 0, errors.New("fake error"))
 	assert.Equal(t, user.Username, a.Username)
 	assert.Equal(t, user.Username, a.Username)
 	assert.Equal(t, 0, len(a.Bucket))
 	assert.Equal(t, 0, len(a.Bucket))
 	assert.Equal(t, 0, len(a.Endpoint))
 	assert.Equal(t, 0, len(a.Endpoint))
 	assert.Equal(t, 0, a.Status)
 	assert.Equal(t, 0, a.Status)
 
 
 	user.FsConfig.Provider = vfs.S3FilesystemProvider
 	user.FsConfig.Provider = vfs.S3FilesystemProvider
-	a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSSH, 123, nil)
+	a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSSH, 123, 0, nil)
 	assert.Equal(t, "s3bucket", a.Bucket)
 	assert.Equal(t, "s3bucket", a.Bucket)
 	assert.Equal(t, "endpoint", a.Endpoint)
 	assert.Equal(t, "endpoint", a.Endpoint)
 	assert.Equal(t, 1, a.Status)
 	assert.Equal(t, 1, a.Status)
 
 
 	user.FsConfig.Provider = vfs.GCSFilesystemProvider
 	user.FsConfig.Provider = vfs.GCSFilesystemProvider
-	a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSCP, 123, ErrQuotaExceeded)
+	a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSCP, 123, 0, ErrQuotaExceeded)
 	assert.Equal(t, "gcsbucket", a.Bucket)
 	assert.Equal(t, "gcsbucket", a.Bucket)
 	assert.Equal(t, 0, len(a.Endpoint))
 	assert.Equal(t, 0, len(a.Endpoint))
 	assert.Equal(t, 2, a.Status)
 	assert.Equal(t, 2, a.Status)
 
 
 	user.FsConfig.Provider = vfs.AzureBlobFilesystemProvider
 	user.FsConfig.Provider = vfs.AzureBlobFilesystemProvider
-	a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSCP, 123, nil)
+	a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSCP, 123, 0, nil)
 	assert.Equal(t, "azcontainer", a.Bucket)
 	assert.Equal(t, "azcontainer", a.Bucket)
 	assert.Equal(t, "azsasurl", a.Endpoint)
 	assert.Equal(t, "azsasurl", a.Endpoint)
 	assert.Equal(t, 1, a.Status)
 	assert.Equal(t, 1, a.Status)
 
 
 	user.FsConfig.AzBlobConfig.SASURL = ""
 	user.FsConfig.AzBlobConfig.SASURL = ""
-	a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSCP, 123, nil)
+	a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSCP, 123, os.O_APPEND, nil)
 	assert.Equal(t, "azcontainer", a.Bucket)
 	assert.Equal(t, "azcontainer", a.Bucket)
 	assert.Equal(t, "azendpoint", a.Endpoint)
 	assert.Equal(t, "azendpoint", a.Endpoint)
 	assert.Equal(t, 1, a.Status)
 	assert.Equal(t, 1, a.Status)
+	assert.Equal(t, os.O_APPEND, a.OpenFlags)
 
 
 	user.FsConfig.Provider = vfs.SFTPFilesystemProvider
 	user.FsConfig.Provider = vfs.SFTPFilesystemProvider
-	a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSFTP, 123, nil)
+	a = newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSFTP, 123, 0, nil)
 	assert.Equal(t, "sftpendpoint", a.Endpoint)
 	assert.Equal(t, "sftpendpoint", a.Endpoint)
 }
 }
 
 
@@ -80,7 +81,7 @@ func TestActionHTTP(t *testing.T) {
 	user := &dataprovider.User{
 	user := &dataprovider.User{
 		Username: "username",
 		Username: "username",
 	}
 	}
-	a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSFTP, 123, nil)
+	a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSFTP, 123, 0, nil)
 	err := actionHandler.Handle(a)
 	err := actionHandler.Handle(a)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
@@ -113,7 +114,7 @@ func TestActionCMD(t *testing.T) {
 	user := &dataprovider.User{
 	user := &dataprovider.User{
 		Username: "username",
 		Username: "username",
 	}
 	}
-	a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSFTP, 123, nil)
+	a := newActionNotification(user, operationDownload, "path", "vpath", "target", "", ProtocolSFTP, 123, 0, nil)
 	err = actionHandler.Handle(a)
 	err = actionHandler.Handle(a)
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 
 
@@ -137,7 +138,7 @@ func TestWrongActions(t *testing.T) {
 		Username: "username",
 		Username: "username",
 	}
 	}
 
 
-	a := newActionNotification(user, operationUpload, "", "", "", "", ProtocolSFTP, 123, nil)
+	a := newActionNotification(user, operationUpload, "", "", "", "", ProtocolSFTP, 123, 0, nil)
 	err := actionHandler.Handle(a)
 	err := actionHandler.Handle(a)
 	assert.Error(t, err, "action with bad command must fail")
 	assert.Error(t, err, "action with bad command must fail")
 
 

+ 1 - 1
common/connection.go

@@ -261,7 +261,7 @@ func (c *BaseConnection) RemoveFile(fs vfs.Fs, fsPath, virtualPath string, info
 	}
 	}
 
 
 	size := info.Size()
 	size := info.Size()
-	actionErr := ExecutePreAction(&c.User, operationPreDelete, fsPath, virtualPath, c.protocol, size)
+	actionErr := ExecutePreAction(&c.User, operationPreDelete, fsPath, virtualPath, c.protocol, size, 0)
 	if actionErr == nil {
 	if actionErr == nil {
 		c.Log(logger.LevelDebug, "remove for path %#v handled by pre-delete action", fsPath)
 		c.Log(logger.LevelDebug, "remove for path %#v handled by pre-delete action", fsPath)
 	} else {
 	} else {

+ 2 - 0
docs/custom-actions.md

@@ -43,6 +43,7 @@ The external program can also read the following environment variables:
 - `SFTPGO_ACTION_ENDPOINT`, non-empty for S3, SFTP and Azure backend if configured. For Azure this is the SAS URL, if configured otherwise the endpoint
 - `SFTPGO_ACTION_ENDPOINT`, non-empty for S3, SFTP and Azure backend if configured. For Azure this is the SAS URL, if configured otherwise the endpoint
 - `SFTPGO_ACTION_STATUS`, integer. Status for `upload`, `download` and `ssh_cmd` actions. 0 means a generic error occurred. 1 means no error, 2 means quota exceeded error
 - `SFTPGO_ACTION_STATUS`, integer. Status for `upload`, `download` and `ssh_cmd` actions. 0 means a generic error occurred. 1 means no error, 2 means quota exceeded error
 - `SFTPGO_ACTION_PROTOCOL`, string. Possible values are `SSH`, `SFTP`, `SCP`, `FTP`, `DAV`, `HTTP`
 - `SFTPGO_ACTION_PROTOCOL`, string. Possible values are `SSH`, `SFTP`, `SCP`, `FTP`, `DAV`, `HTTP`
+- `SFTPGO_ACTION_OPEN_FLAGS`, integer. File open flags, can be non-zero for `pre-upload` action. If `SFTPGO_ACTION_FILE_SIZE` is greater than zero and `SFTPGO_ACTION_OPEN_FLAGS&512 == 0` the target file will not be truncated
 
 
 Previous global environment variables aren't cleared when the script is called.
 Previous global environment variables aren't cleared when the script is called.
 The program must finish within 30 seconds.
 The program must finish within 30 seconds.
@@ -60,6 +61,7 @@ If the `hook` defines an HTTP URL then this URL will be invoked as HTTP POST. Th
 - `endpoint`, included for S3, SFTP and Azure backend if configured. For Azure this is the SAS URL, if configured, otherwise the endpoint
 - `endpoint`, included for S3, SFTP and Azure backend if configured. For Azure this is the SAS URL, if configured, otherwise the endpoint
 - `status`, integer. Status for `upload`, `download` and `ssh_cmd` actions. 0 means a generic error occurred. 1 means no error, 2 means quota exceeded error
 - `status`, integer. Status for `upload`, `download` and `ssh_cmd` actions. 0 means a generic error occurred. 1 means no error, 2 means quota exceeded error
 - `protocol`, string. Possible values are `SSH`, `SFTP`, `SCP`, `FTP`, `DAV`, `HTTP`
 - `protocol`, string. Possible values are `SSH`, `SFTP`, `SCP`, `FTP`, `DAV`, `HTTP`
+- `open_flags`, integer, File open flags, can be non-zero for `pre-upload` action. If `file_size` is greater than zero and `file_size&512 == 0` the target file will not be truncated
 
 
 The HTTP hook will use the global configuration for HTTP clients and will respect the retry configurations.
 The HTTP hook will use the global configuration for HTTP clients and will respect the retry configurations.
 
 

+ 3 - 3
ftpd/handler.go

@@ -297,7 +297,7 @@ func (c *Connection) downloadFile(fs vfs.Fs, fsPath, ftpPath string, offset int6
 		return nil, c.GetPermissionDeniedError()
 		return nil, c.GetPermissionDeniedError()
 	}
 	}
 
 
-	if err := common.ExecutePreAction(&c.User, common.OperationPreDownload, fsPath, ftpPath, c.GetProtocol(), 0); err != nil {
+	if err := common.ExecutePreAction(&c.User, common.OperationPreDownload, fsPath, ftpPath, c.GetProtocol(), 0, 0); err != nil {
 		c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", ftpPath, err)
 		c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", ftpPath, err)
 		return nil, c.GetPermissionDeniedError()
 		return nil, c.GetPermissionDeniedError()
 	}
 	}
@@ -358,7 +358,7 @@ func (c *Connection) handleFTPUploadToNewFile(fs vfs.Fs, resolvedPath, filePath,
 		c.Log(logger.LevelInfo, "denying file write due to quota limits")
 		c.Log(logger.LevelInfo, "denying file write due to quota limits")
 		return nil, common.ErrQuotaExceeded
 		return nil, common.ErrQuotaExceeded
 	}
 	}
-	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), 0); err != nil {
+	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), 0, 0); err != nil {
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		return nil, c.GetPermissionDeniedError()
 		return nil, c.GetPermissionDeniedError()
 	}
 	}
@@ -388,7 +388,7 @@ func (c *Connection) handleFTPUploadToExistingFile(fs vfs.Fs, flags int, resolve
 		c.Log(logger.LevelInfo, "denying file write due to quota limits")
 		c.Log(logger.LevelInfo, "denying file write due to quota limits")
 		return nil, common.ErrQuotaExceeded
 		return nil, common.ErrQuotaExceeded
 	}
 	}
-	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), fileSize); err != nil {
+	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), fileSize, flags); err != nil {
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		return nil, c.GetPermissionDeniedError()
 		return nil, c.GetPermissionDeniedError()
 	}
 	}

+ 1 - 1
httpd/handler.go

@@ -93,7 +93,7 @@ func (c *Connection) getFileReader(name string, offset int64, method string) (io
 	}
 	}
 
 
 	if method != http.MethodHead {
 	if method != http.MethodHead {
-		if err := common.ExecutePreAction(&c.User, common.OperationPreDownload, p, name, c.GetProtocol(), 0); err != nil {
+		if err := common.ExecutePreAction(&c.User, common.OperationPreDownload, p, name, c.GetProtocol(), 0, 0); err != nil {
 			c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", name, err)
 			c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", name, err)
 			return nil, c.GetPermissionDeniedError()
 			return nil, c.GetPermissionDeniedError()
 		}
 		}

+ 4 - 4
sftpd/handler.go

@@ -59,7 +59,7 @@ func (c *Connection) Fileread(request *sftp.Request) (io.ReaderAt, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if err := common.ExecutePreAction(&c.User, common.OperationPreDownload, p, request.Filepath, c.GetProtocol(), 0); err != nil {
+	if err := common.ExecutePreAction(&c.User, common.OperationPreDownload, p, request.Filepath, c.GetProtocol(), 0, 0); err != nil {
 		c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", request.Filepath, err)
 		c.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", request.Filepath, err)
 		return nil, c.GetPermissionDeniedError()
 		return nil, c.GetPermissionDeniedError()
 	}
 	}
@@ -330,7 +330,7 @@ func (c *Connection) handleSFTPUploadToNewFile(fs vfs.Fs, resolvedPath, filePath
 		return nil, sftp.ErrSSHFxFailure
 		return nil, sftp.ErrSSHFxFailure
 	}
 	}
 
 
-	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), 0); err != nil {
+	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), 0, 0); err != nil {
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		return nil, c.GetPermissionDeniedError()
 		return nil, c.GetPermissionDeniedError()
 	}
 	}
@@ -361,13 +361,13 @@ func (c *Connection) handleSFTPUploadToExistingFile(fs vfs.Fs, pflags sftp.FileO
 		c.Log(logger.LevelInfo, "denying file write due to quota limits")
 		c.Log(logger.LevelInfo, "denying file write due to quota limits")
 		return nil, sftp.ErrSSHFxFailure
 		return nil, sftp.ErrSSHFxFailure
 	}
 	}
-	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), fileSize); err != nil {
+	osFlags := getOSOpenFlags(pflags)
+	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), fileSize, osFlags); err != nil {
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		return nil, c.GetPermissionDeniedError()
 		return nil, c.GetPermissionDeniedError()
 	}
 	}
 
 
 	minWriteOffset := int64(0)
 	minWriteOffset := int64(0)
-	osFlags := getOSOpenFlags(pflags)
 	isTruncate := osFlags&os.O_TRUNC != 0
 	isTruncate := osFlags&os.O_TRUNC != 0
 	// for upload resumes OpenSSH sets the APPEND flag while WinSCP does not set it,
 	// for upload resumes OpenSSH sets the APPEND flag while WinSCP does not set it,
 	// so we suppose this is an upload resume if the TRUNCATE flag is not set
 	// so we suppose this is an upload resume if the TRUNCATE flag is not set

+ 2 - 2
sftpd/scp.go

@@ -219,7 +219,7 @@ func (c *scpCommand) handleUploadFile(fs vfs.Fs, resolvedPath, filePath string,
 		c.sendErrorMessage(fs, err)
 		c.sendErrorMessage(fs, err)
 		return err
 		return err
 	}
 	}
-	err := common.ExecutePreAction(&c.connection.User, common.OperationPreUpload, resolvedPath, requestPath, c.connection.GetProtocol(), fileSize)
+	err := common.ExecutePreAction(&c.connection.User, common.OperationPreUpload, resolvedPath, requestPath, c.connection.GetProtocol(), fileSize, os.O_TRUNC)
 	if err != nil {
 	if err != nil {
 		c.connection.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		c.connection.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		err = c.connection.GetPermissionDeniedError()
 		err = c.connection.GetPermissionDeniedError()
@@ -514,7 +514,7 @@ func (c *scpCommand) handleDownload(filePath string) error {
 		return common.ErrPermissionDenied
 		return common.ErrPermissionDenied
 	}
 	}
 
 
-	if err := common.ExecutePreAction(&c.connection.User, common.OperationPreDownload, p, filePath, c.connection.GetProtocol(), 0); err != nil {
+	if err := common.ExecutePreAction(&c.connection.User, common.OperationPreDownload, p, filePath, c.connection.GetProtocol(), 0, 0); err != nil {
 		c.connection.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", filePath, err)
 		c.connection.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", filePath, err)
 		c.sendErrorMessage(fs, common.ErrPermissionDenied)
 		c.sendErrorMessage(fs, common.ErrPermissionDenied)
 		return common.ErrPermissionDenied
 		return common.ErrPermissionDenied

+ 1 - 1
webdavd/file.go

@@ -148,7 +148,7 @@ func (f *webDavFile) Read(p []byte) (n int, err error) {
 			return 0, f.Connection.GetPermissionDeniedError()
 			return 0, f.Connection.GetPermissionDeniedError()
 		}
 		}
 		err := common.ExecutePreAction(&f.Connection.User, common.OperationPreDownload, f.GetFsPath(), f.GetVirtualPath(),
 		err := common.ExecutePreAction(&f.Connection.User, common.OperationPreDownload, f.GetFsPath(), f.GetVirtualPath(),
-			f.Connection.GetProtocol(), 0)
+			f.Connection.GetProtocol(), 0, 0)
 		if err != nil {
 		if err != nil {
 			f.Connection.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", f.GetVirtualPath(), err)
 			f.Connection.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", f.GetVirtualPath(), err)
 			return 0, f.Connection.GetPermissionDeniedError()
 			return 0, f.Connection.GetPermissionDeniedError()

+ 2 - 2
webdavd/handler.go

@@ -194,7 +194,7 @@ func (c *Connection) handleUploadToNewFile(fs vfs.Fs, resolvedPath, filePath, re
 		c.Log(logger.LevelInfo, "denying file write due to quota limits")
 		c.Log(logger.LevelInfo, "denying file write due to quota limits")
 		return nil, common.ErrQuotaExceeded
 		return nil, common.ErrQuotaExceeded
 	}
 	}
-	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), 0); err != nil {
+	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), 0, 0); err != nil {
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		return nil, c.GetPermissionDeniedError()
 		return nil, c.GetPermissionDeniedError()
 	}
 	}
@@ -223,7 +223,7 @@ func (c *Connection) handleUploadToExistingFile(fs vfs.Fs, resolvedPath, filePat
 		c.Log(logger.LevelInfo, "denying file write due to quota limits")
 		c.Log(logger.LevelInfo, "denying file write due to quota limits")
 		return nil, common.ErrQuotaExceeded
 		return nil, common.ErrQuotaExceeded
 	}
 	}
-	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), fileSize); err != nil {
+	if err := common.ExecutePreAction(&c.User, common.OperationPreUpload, resolvedPath, requestPath, c.GetProtocol(), fileSize, os.O_TRUNC); err != nil {
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		c.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
 		return nil, c.GetPermissionDeniedError()
 		return nil, c.GetPermissionDeniedError()
 	}
 	}