-
Notifications
You must be signed in to change notification settings - Fork 380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memfile stuff #561
base: master
Are you sure you want to change the base?
Memfile stuff #561
Changes from all commits
b9d7f36
8513fed
07a6b6a
7bf7a25
6b2b978
688c055
a0a4a52
8ee6563
f215740
d41c7d4
87fa218
a5d4316
4404cc8
656a9db
b1d53f7
cbf7fcd
4b73c93
82cd5ca
5fd4ff4
660c973
6c452cc
6563249
ad0d7df
7e1a518
d3a55c7
bff300b
1d040d6
706f4f1
1ae2738
3d7324a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,31 +54,10 @@ func marshalFileInfo(b []byte, fi os.FileInfo) []byte { | |
// so that number of pairs equals extended_count | ||
|
||
flags, fileStat := fileStatFromInfo(fi) | ||
f := newFileAttrFlags(flags) | ||
|
||
b = marshalUint32(b, flags) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See? Think about what if We’re going to encode a corrupted packet. 🤦♀️ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thankfully, that's not actually possible, but why it's not possible is subtle:
That's from fileStatFromInfo. So it's not possible to have sshFileXferAttrExtended set while len(fileStat.Extended) == 0. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, for |
||
if flags&sshFileXferAttrSize != 0 { | ||
b = marshalUint64(b, fileStat.Size) | ||
} | ||
if flags&sshFileXferAttrUIDGID != 0 { | ||
b = marshalUint32(b, fileStat.UID) | ||
b = marshalUint32(b, fileStat.GID) | ||
} | ||
if flags&sshFileXferAttrPermissions != 0 { | ||
b = marshalUint32(b, fileStat.Mode) | ||
} | ||
if flags&sshFileXferAttrACmodTime != 0 { | ||
b = marshalUint32(b, fileStat.Atime) | ||
b = marshalUint32(b, fileStat.Mtime) | ||
} | ||
|
||
if flags&sshFileXferAttrExtended != 0 { | ||
b = marshalUint32(b, uint32(len(fileStat.Extended))) | ||
|
||
for _, attr := range fileStat.Extended { | ||
b = marshalString(b, attr.ExtType) | ||
b = marshalString(b, attr.ExtData) | ||
} | ||
} | ||
b = fileStat.MarshalTo(b, f) | ||
|
||
return b | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,7 +37,8 @@ func (fs *root) Fileread(r *Request) (io.ReaderAt, error) { | |
return nil, os.ErrInvalid | ||
} | ||
|
||
return fs.OpenFile(r) | ||
// Needs to be readable by the owner. | ||
return fs.openFileModeCheck(r, 0o400) | ||
} | ||
|
||
func (fs *root) Filewrite(r *Request) (io.WriterAt, error) { | ||
|
@@ -47,10 +48,16 @@ func (fs *root) Filewrite(r *Request) (io.WriterAt, error) { | |
return nil, os.ErrInvalid | ||
} | ||
|
||
return fs.OpenFile(r) | ||
// Needs to be writable by the owner. | ||
return fs.openFileModeCheck(r, 0o200) | ||
} | ||
|
||
func (fs *root) OpenFile(r *Request) (WriterAtReaderAt, error) { | ||
// Needs to be readable and writable by the owner. | ||
return fs.openFileModeCheck(r, 0o200|0o400) | ||
} | ||
|
||
func (fs *root) openFileModeCheck(r *Request, mode uint32) (WriterAtReaderAt, error) { | ||
if fs.mockErr != nil { | ||
return nil, fs.mockErr | ||
} | ||
|
@@ -59,7 +66,16 @@ func (fs *root) OpenFile(r *Request) (WriterAtReaderAt, error) { | |
fs.mu.Lock() | ||
defer fs.mu.Unlock() | ||
|
||
return fs.openfile(r.Filepath, r.Flags) | ||
f, err := fs.openfile(r.Filepath, r.Flags) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if f.mode&mode != mode { | ||
return nil, os.ErrPermission | ||
} | ||
|
||
return f, nil | ||
} | ||
|
||
func (fs *root) putfile(pathname string, file *memFile) error { | ||
|
@@ -72,7 +88,7 @@ func (fs *root) putfile(pathname string, file *memFile) error { | |
return os.ErrInvalid | ||
} | ||
|
||
if _, err := fs.lfetch(pathname); err != os.ErrNotExist { | ||
if _, err := fs.lfetch(pathname); !errors.Is(err, os.ErrNotExist) { | ||
return os.ErrExist | ||
} | ||
|
||
|
@@ -108,8 +124,10 @@ func (fs *root) openfile(pathname string, flags uint32) (*memFile, error) { | |
link, err = fs.lfetch(pathname) | ||
} | ||
|
||
// The mode is currently hard coded because this library doesn't parse out the mode at file open time. | ||
file := &memFile{ | ||
modtime: time.Now(), | ||
mode: 0644, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should not be defaulting this value. Please, pass it as a parameter, and document in the godoc that it is ignored if the creation flag is not set. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough, I had defaulted to the value that we previously hard coded. I'll take a crack at getting it from the initial request. |
||
} | ||
|
||
if err := fs.putfile(pathname, file); err != nil { | ||
|
@@ -151,15 +169,30 @@ func (fs *root) Filecmd(r *Request) error { | |
|
||
switch r.Method { | ||
case "Setstat": | ||
// Some notes: | ||
// | ||
// openfile will follow symlinks, however as best as I can tell this is the correct POSIX behavior for chmod. | ||
// | ||
// openfile does not currently support opening a directory, and at this time we do not implement directory permissions. | ||
flags := r.AttrFlags() | ||
attrs := r.Attributes() | ||
file, err := fs.openfile(r.Filepath, sshFxfWrite) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if r.AttrFlags().Size { | ||
return file.Truncate(int64(r.Attributes().Size)) | ||
if flags.Size { | ||
if err := file.Truncate(int64(attrs.Size)); err != nil { | ||
return err | ||
} | ||
} | ||
if flags.Permissions { | ||
file.chmod(attrs.Mode) | ||
} | ||
// We only have mtime, not atime. | ||
if flags.Acmodtime { | ||
file.modtime = time.Unix(int64(attrs.Mtime), 0) | ||
} | ||
|
||
return nil | ||
|
||
case "Rename": | ||
|
@@ -209,7 +242,7 @@ func (fs *root) rename(oldpath, newpath string) error { | |
} | ||
|
||
target, err := fs.lfetch(newpath) | ||
if err != os.ErrNotExist { | ||
if !errors.Is(err, os.ErrNotExist) { | ||
if target == file { | ||
// IEEE 1003.1: if oldpath and newpath are the same directory entry, | ||
// then return no error, and perform no further action. | ||
|
@@ -507,7 +540,7 @@ func (fs *root) exists(path string) bool { | |
|
||
_, err = fs.lfetch(path) | ||
|
||
return err != os.ErrNotExist | ||
return !errors.Is(err, os.ErrNotExist) | ||
} | ||
|
||
func (fs *root) fetch(pathname string) (*memFile, error) { | ||
|
@@ -544,6 +577,7 @@ type memFile struct { | |
modtime time.Time | ||
symlink string | ||
isdir bool | ||
mode uint32 | ||
|
||
mu sync.RWMutex | ||
content []byte | ||
|
@@ -563,13 +597,15 @@ func (f *memFile) Size() int64 { | |
return f.size() | ||
} | ||
func (f *memFile) Mode() os.FileMode { | ||
// At this time, we do not implement directory modes. | ||
if f.isdir { | ||
return os.FileMode(0755) | os.ModeDir | ||
} | ||
// Under POSIX, symlinks have a fixed mode which can not be changed. | ||
if f.symlink != "" { | ||
return os.FileMode(0777) | os.ModeSymlink | ||
} | ||
return os.FileMode(0644) | ||
return os.FileMode(f.mode) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function also now needs to that directories might have non-default modes. |
||
} | ||
func (f *memFile) ModTime() time.Time { return f.modtime } | ||
func (f *memFile) IsDir() bool { return f.isdir } | ||
|
@@ -645,3 +681,8 @@ func (f *memFile) TransferError(err error) { | |
|
||
f.err = err | ||
} | ||
|
||
func (f *memFile) chmod(mode uint32) { | ||
const mask = uint32(os.ModePerm | s_ISUID | s_ISGID | s_ISVTX) | ||
f.mode = (f.mode &^ mask) | (mode & mask) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And… 🤦♀️ we run into another bug of design.
The problem here is that we’re going to need to Marshal
flags
itself based on ifls(fs.Extended)
is set or not. 😐This split implementation is really going to drive me nuts, and might just drive me mad enough to go ahead and just roll out v2…