Skip to content

Commit

Permalink
Convert stat and statfs to api_method (#15076)
Browse files Browse the repository at this point in the history
This commit converts filesystem.stat and filesystem.statfs to new
api_method.
  • Loading branch information
anodos325 authored Dec 3, 2024
1 parent 2670e83 commit eecc730
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 62 deletions.
131 changes: 124 additions & 7 deletions src/middlewared/middlewared/api/v25_04_0/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
query_result
)
from pydantic import Field, model_validator
from typing import Literal, Self
from typing import Any, Literal, Self
from middlewared.utils.filesystem.acl import (
ACL_UNDEFINED_ID,
)
Expand All @@ -21,6 +21,8 @@
'FilesystemSetPermArgs', 'FilesystemSetPermResult',
'FilesystemListdirArgs', 'FilesystemListdirResult',
'FilesystemMkdirArgs', 'FilesystemMkdirResult',
'FilesystemStatArgs', 'FilesystemStatResult',
'FilesystemStatfsArgs', 'FilesystemStatfsResult',
]


Expand Down Expand Up @@ -118,19 +120,22 @@ class FilesystemSetPermResult(BaseModel):
]


FileType = Literal[
StatxEtype.DIRECTORY,
StatxEtype.FILE,
StatxEtype.SYMLINK,
StatxEtype.OTHER,
]


class FilesystemDirEntry(BaseModel):
name: NonEmptyString
""" Entry's base name. """
path: NonEmptyString
""" Entry's full path. """
realpath: NonEmptyString
""" Canonical path of the entry, eliminating any symbolic links"""
type: Literal[
StatxEtype.DIRECTORY,
StatxEtype.FILE,
StatxEtype.SYMLINK,
StatxEtype.OTHER,
]
type: FileType
size: int
""" Size in bytes of a plain file. This corresonds with stx_size. """
allocation_size: int
Expand Down Expand Up @@ -181,3 +186,115 @@ class FilesystemMkdirArgs(BaseModel):

class FilesystemMkdirResult(BaseModel):
result: FilesystemDirEntry


class FilesystemStatData(BaseModel):
realpath: NonEmptyString
""" Canonical path of the entry, eliminating any symbolic links"""
type: FileType
size: int
""" Size in bytes of a plain file. This corresonds with stx_size. """
allocation_size: int
""" Allocated size of file. Calculated by multiplying stx_blocks by 512. """
mode: int
""" Entry's mode including file type information and file permission bits. This corresponds with stx_mode. """
mount_id: int
""" The mount ID of the mount containing the entry. This corresponds to the number in first
field of /proc/self/mountinfo and stx_mnt_id. """
uid: int
""" User ID of the entry's owner. This corresponds with stx_uid. """
gid: int
""" Group ID of the entry's owner. This corresponds with stx_gid. """
atime: float
""" Time of last access. Corresponds with stx_atime. This is mutable from userspace. """
mtime: float
""" Time of last modification. Corresponds with stx_mtime. This is mutable from userspace. """
ctime: float
""" Time of last status change. Corresponds with stx_ctime. """
btime: float
""" Time of creation. Corresponds with stx_btime. """
dev: int
""" The ID of the device containing the filesystem where the file resides. This is not sufficient to uniquely
identify a particular filesystem mount. mount_id must be used for that purpose. This corresponds with st_dev. """
inode: int
""" The inode number of the file. This corresponds with stx_ino. """
nlink: int
""" Number of hard links. Corresponds with stx_nlinks. """
acl: bool
""" Specifies whether ACL is present on the entry. If this is the case then file permission
bits as reported in `mode` may not be representative of the actual permissions. """
is_mountpoint: bool
""" Specifies whether the entry is also the mountpoint of a filesystem. """
is_ctldir: bool
""" Specifies whether the entry is located within the ZFS ctldir (for example a snapshot). """
attributes: list[FILESYSTEM_STATX_ATTRS]
""" Extra file attribute indicators for entry as returned by statx. Expanded from stx_attributes. """
user: NonEmptyString | None
""" Username associated with `uid`. Will be None if the User ID does not map to existing user. """
group: NonEmptyString | None
""" Groupname associated with `gid`. Will be None if the Group ID does not map to existing group. """


class FilesystemStatArgs(BaseModel):
path: NonEmptyString


class FilesystemStatResult(BaseModel):
result: FilesystemStatData


StatfsFlags = Literal[
'RW', 'RO',
'XATTR',
'NOACL', 'NFS4ACL', 'POSIXACL',
'CASESENSITIVE', 'CASEINSENSITIVE',
'NOATIME', 'RELATIME',
'NOSUID', 'NODEV', 'NOEXEC',
]


StatfsFstype = Literal['zfs', 'tmpfs']


class FilesystemStatfsData(BaseModel):
flags: list[StatfsFlags | Any] # ANY is here because we can't predict what random FS will have
""" Combined per-mount options and per-superblock options for mounted filesystem. """
fsid: NonEmptyString
""" Unique filesystem ID as returned by statvfs. """
fstype: StatfsFlags | Any # Same as with flags
""" String representation of filesystem type from mountinfo. """
source: NonEmptyString
""" Source for the mounted filesystem. For ZFS this will be dataset name. """
dest: NonEmptyString
""" Local path on which filesystem is mounted. """
blocksize: int
""" Filesystem block size as reported by statvfs. """
total_blocks: int
""" Filesystem size as reported in blocksize blocks as reported by statvfs. """
free_blocks: int
""" Number of free blocks as reported by statvfs. """
avail_blocks: int
""" Number of available blocks as reported by statvfs. """
total_blocks_str: NonEmptyString
free_blocks_str: NonEmptyString
avail_blocks_str: NonEmptyString
files: int
""" Number of inodes in use as reported by statvfs. """
free_files: int
""" Number of free inodes as reported by statvfs. """
name_max: int
""" Maximum filename length as reported by statvfs. """
total_bytes: int
free_bytes: int
avail_bytes: int
total_bytes_str: NonEmptyString
free_bytes_str: NonEmptyString
avail_bytes_str: NonEmptyString


class FilesystemStatfsArgs(BaseModel):
path: NonEmptyString


class FilesystemStatfsResult(BaseModel):
result: FilesystemStatfsData
61 changes: 6 additions & 55 deletions src/middlewared/middlewared/plugins/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
from middlewared.api.current import (
FilesystemListdirArgs, FilesystemListdirResult,
FilesystemMkdirArgs, FilesystemMkdirResult,
FilesystemStatArgs, FilesystemStatResult,
FilesystemStatfsArgs, FilesystemStatfsResult,
)
from middlewared.event import EventSource
from middlewared.plugins.pwenc import PWENC_FILE_SECRET, PWENC_FILE_SECRET_MODE
from middlewared.plugins.docker.state_utils import IX_APPS_DIR_NAME
from middlewared.schema import accepts, Bool, Dict, Float, Int, List, Ref, returns, Path, Str
from middlewared.schema import accepts, Bool, Dict, Int, Ref, returns, Path, Str
from middlewared.service import private, CallError, filterable, Service, job
from middlewared.utils import filter_list
from middlewared.utils.filesystem import attrs, stat_x
Expand Down Expand Up @@ -299,34 +301,7 @@ def listdir(self, path, filters, options):
with DirectoryIterator(path, file_type=file_type, request_mask=request_mask) as d_iter:
return filter_list(d_iter, filters, options)

@accepts(Str('path'), roles=['FILESYSTEM_ATTRS_READ'])
@returns(Dict(
'path_stats',
Str('realpath', required=True),
Int('size', required=True),
Int('allocation_size', required=True),
Int('mode', required=True),
Int('uid', required=True),
Int('gid', required=True),
Float('atime', required=True),
Float('mtime', required=True),
Float('ctime', required=True),
Float('btime', required=True),
Int('dev', required=True),
Int('mount_id', required=True),
Int('inode', required=True),
Int('nlink', required=True),
Bool('is_mountpoint', required=True),
Bool('is_ctldir', required=True),
List(
'attributes',
required=True,
items=[Str('statx_attribute', enum=[attr.name for attr in stat_x.StatxAttr])]
),
Str('user', null=True, required=True),
Str('group', null=True, required=True),
Bool('acl', required=True),
))
@api_method(FilesystemStatArgs, FilesystemStatResult, roles=['FILESYSTEM_ATTRS_READ'])
def stat(self, _path):
"""
Return filesystem information for a given path.
Expand Down Expand Up @@ -512,31 +487,7 @@ def put(self, job, path, options):
os.chmod(path, mode)
return True

@accepts(Str('path'), roles=['FILESYSTEM_ATTRS_READ'])
@returns(Dict(
'path_statfs',
List('flags', required=True),
List('fsid', required=True),
Str('fstype', required=True),
Str('source', required=True),
Str('dest', required=True),
Int('blocksize', required=True),
Int('total_blocks', required=True),
Int('free_blocks', required=True),
Int('avail_blocks', required=True),
Str('total_blocks_str', required=True),
Str('free_blocks_str', required=True),
Str('avail_blocks_str', required=True),
Int('files', required=True),
Int('free_files', required=True),
Int('name_max', required=True),
Int('total_bytes', required=True),
Int('free_bytes', required=True),
Int('avail_bytes', required=True),
Str('total_bytes_str', required=True),
Str('free_bytes_str', required=True),
Str('avail_bytes_str', required=True),
))
@api_method(FilesystemStatfsArgs, FilesystemStatfsResult, roles=['FILESYSTEM_ATTRS_READ'])
def statfs(self, path):
"""
Return stats from the filesystem of a given path.
Expand Down Expand Up @@ -579,7 +530,7 @@ def statfs(self, path):
'files': st.f_files,
'free_files': st.f_ffree,
'name_max': st.f_namemax,
'fsid': [str(st.f_fsid)],
'fsid': str(st.f_fsid),
'total_bytes': st.f_blocks * st.f_frsize,
'free_bytes': st.f_bfree * st.f_frsize,
'avail_bytes': st.f_bavail * st.f_frsize,
Expand Down

0 comments on commit eecc730

Please sign in to comment.