mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add p9.OpenTruncate.
This is required to implement O_TRUNC correctly on filesystems backed by gofers. 9P2000.L: "lopen prepares fid for file I/O. flags contains Linux open(2) flags bits, e.g. O_RDONLY, O_RDWR, O_WRONLY." open(2): "The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR. ... In addition, zero or more file creation flags and file status flags can be bitwise-or'd in flags." The reference 9P2000.L implementation also appears to expect arbitrary flags, not just access modes, in Tlopen.flags: https://github.com/chaos/diod/blob/master/diod/ops.c#L703 PiperOrigin-RevId: 278972683
This commit is contained in:
+1
-1
@@ -116,7 +116,7 @@ type File interface {
|
||||
// N.B. The server must resolve any lazy paths when open is called.
|
||||
// After this point, read and write may be called on files with no
|
||||
// deletion check, so resolving in the data path is not viable.
|
||||
Open(mode OpenFlags) (*fd.FD, QID, uint32, error)
|
||||
Open(flags OpenFlags) (*fd.FD, QID, uint32, error)
|
||||
|
||||
// Read reads from this file. Open must be called first.
|
||||
//
|
||||
|
||||
+24
-13
@@ -32,18 +32,22 @@ import (
|
||||
type OpenFlags uint32
|
||||
|
||||
const (
|
||||
// ReadOnly is a Topen and Tcreate flag indicating read-only mode.
|
||||
// ReadOnly is a Tlopen and Tlcreate flag indicating read-only mode.
|
||||
ReadOnly OpenFlags = 0
|
||||
|
||||
// WriteOnly is a Topen and Tcreate flag indicating write-only mode.
|
||||
// WriteOnly is a Tlopen and Tlcreate flag indicating write-only mode.
|
||||
WriteOnly OpenFlags = 1
|
||||
|
||||
// ReadWrite is a Topen flag indicates read-write mode.
|
||||
// ReadWrite is a Tlopen flag indicates read-write mode.
|
||||
ReadWrite OpenFlags = 2
|
||||
|
||||
// OpenFlagsModeMask is a mask of valid OpenFlags mode bits.
|
||||
OpenFlagsModeMask OpenFlags = 3
|
||||
|
||||
// OpenTruncate is a Tlopen flag indicating that the opened file should be
|
||||
// truncated.
|
||||
OpenTruncate OpenFlags = 01000
|
||||
|
||||
// OpenFlagsIgnoreMask is a list of OpenFlags mode bits that are ignored for Tlopen.
|
||||
// Note that syscall.O_LARGEFILE is set to zero, use value from Linux fcntl.h.
|
||||
OpenFlagsIgnoreMask OpenFlags = syscall.O_DIRECTORY | syscall.O_NOATIME | 0100000
|
||||
@@ -71,25 +75,32 @@ const (
|
||||
|
||||
// OSFlags converts a p9.OpenFlags to an int compatible with open(2).
|
||||
func (o OpenFlags) OSFlags() int {
|
||||
return int(o & OpenFlagsModeMask)
|
||||
// "flags contains Linux open(2) flags bits" - 9P2000.L
|
||||
return int(o)
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (o OpenFlags) String() string {
|
||||
switch o {
|
||||
var buf strings.Builder
|
||||
switch mode := o & OpenFlagsModeMask; mode {
|
||||
case ReadOnly:
|
||||
return "ReadOnly"
|
||||
buf.WriteString("ReadOnly")
|
||||
case WriteOnly:
|
||||
return "WriteOnly"
|
||||
buf.WriteString("WriteOnly")
|
||||
case ReadWrite:
|
||||
return "ReadWrite"
|
||||
case OpenFlagsModeMask:
|
||||
return "OpenFlagsModeMask"
|
||||
case OpenFlagsIgnoreMask:
|
||||
return "OpenFlagsIgnoreMask"
|
||||
buf.WriteString("ReadWrite")
|
||||
default:
|
||||
return "UNDEFINED"
|
||||
fmt.Fprintf(&buf, "%#o", mode)
|
||||
}
|
||||
otherFlags := o &^ OpenFlagsModeMask
|
||||
if otherFlags&OpenTruncate != 0 {
|
||||
buf.WriteString("|OpenTruncate")
|
||||
otherFlags &^= OpenTruncate
|
||||
}
|
||||
if otherFlags != 0 {
|
||||
fmt.Fprintf(&buf, "|%#o", otherFlags)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Tag is a message tag.
|
||||
|
||||
@@ -366,23 +366,24 @@ func fchown(fd int, uid p9.UID, gid p9.GID) error {
|
||||
}
|
||||
|
||||
// Open implements p9.File.
|
||||
func (l *localFile) Open(mode p9.OpenFlags) (*fd.FD, p9.QID, uint32, error) {
|
||||
func (l *localFile) Open(flags p9.OpenFlags) (*fd.FD, p9.QID, uint32, error) {
|
||||
if l.isOpen() {
|
||||
panic(fmt.Sprintf("attempting to open already opened file: %q", l.hostPath))
|
||||
}
|
||||
|
||||
// Check if control file can be used or if a new open must be created.
|
||||
var newFile *fd.FD
|
||||
if mode == p9.ReadOnly {
|
||||
log.Debugf("Open reusing control file, mode: %v, %q", mode, l.hostPath)
|
||||
if flags == p9.ReadOnly {
|
||||
log.Debugf("Open reusing control file, flags: %v, %q", flags, l.hostPath)
|
||||
newFile = l.file
|
||||
} else {
|
||||
// Ideally reopen would call name_to_handle_at (with empty name) and
|
||||
// open_by_handle_at to reopen the file without using 'hostPath'. However,
|
||||
// name_to_handle_at and open_by_handle_at aren't supported by overlay2.
|
||||
log.Debugf("Open reopening file, mode: %v, %q", mode, l.hostPath)
|
||||
log.Debugf("Open reopening file, flags: %v, %q", flags, l.hostPath)
|
||||
var err error
|
||||
newFile, err = reopenProcFd(l.file, openFlags|mode.OSFlags())
|
||||
// Constrain open flags to the open mode and O_TRUNC.
|
||||
newFile, err = reopenProcFd(l.file, openFlags|(flags.OSFlags()&(syscall.O_ACCMODE|syscall.O_TRUNC)))
|
||||
if err != nil {
|
||||
return nil, p9.QID{}, 0, extractErrno(err)
|
||||
}
|
||||
@@ -409,7 +410,7 @@ func (l *localFile) Open(mode p9.OpenFlags) (*fd.FD, p9.QID, uint32, error) {
|
||||
}
|
||||
l.file = newFile
|
||||
}
|
||||
l.mode = mode
|
||||
l.mode = flags & p9.OpenFlagsModeMask
|
||||
return fd, l.attachPoint.makeQID(stat), 0, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user