1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
|
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fuseops
import (
"fmt"
"os"
"time"
"github.com/jacobsa/fuse/internal/fusekernel"
)
// InodeID is a 64-bit number used to uniquely identify a file or directory in
// the file system. File systems may mint inode IDs with any value except for
// RootInodeID.
//
// This corresponds to struct inode::i_no in the VFS layer.
// (https://tinyurl.com/23sr9svd)
type InodeID uint64
// RootInodeID is a distinguished inode ID that identifies the root of the file
// system, e.g. in an OpenDirOp or LookUpInodeOp. Unlike all other inode IDs,
// which are minted by the file system, the FUSE VFS layer may send a request
// for this ID without the file system ever having referenced it in a previous
// response.
const RootInodeID = 1
func init() {
// Make sure the constant above is correct. We do this at runtime rather than
// defining the constant in terms of fusekernel.RootID for two reasons:
//
// 1. Users can more clearly see that the root ID is low and can therefore
// be used as e.g. an array index, with space reserved up to the root.
//
// 2. The constant can be untyped and can therefore more easily be used as
// an array index.
//
if RootInodeID != fusekernel.RootID {
panic(
fmt.Sprintf(
"Oops, RootInodeID is wrong: %v vs. %v",
RootInodeID,
fusekernel.RootID))
}
}
// InodeAttributes contains attributes for a file or directory inode. It
// corresponds to struct inode (https://tinyurl.com/23sr9svd).
type InodeAttributes struct {
Size uint64
// The number of incoming hard links to this inode.
Nlink uint32
// The mode of the inode. This is exposed to the user in e.g. the result of
// fstat(2).
//
// Note that in contrast to the defaults for FUSE, this package mounts file
// systems in a manner such that the kernel checks inode permissions in the
// standard posix way. This is implemented by setting the default_permissions
// mount option (https://tinyurl.com/ytun2zsn, https://tinyurl.com/52hz9vya).
//
// For example, in the case of mkdir:
//
// * (https://tinyurl.com/4yp9bu3h) sys_mkdirat calls inode_permission.
//
// * (...) inode_permission eventually calls do_inode_permission.
//
// * (https://tinyurl.com/5f9k2eya) calls i_op->permission, which is
// fuse_permission (https://tinyurl.com/4kevbw27).
//
// * (https://tinyurl.com/nfea3pwj) fuse_permission doesn't do anything at
// all for several code paths if FUSE_DEFAULT_PERMISSIONS is unset. In
// contrast, if that flag *is* set, then it calls generic_permission.
//
Mode os.FileMode
// The device number. Only valid if the file is a device
Rdev uint32
// Time information. See `man 2 stat` for full details.
Atime time.Time // Time of last access
Mtime time.Time // Time of last modification
Ctime time.Time // Time of last modification to inode
Crtime time.Time // Time of creation (OS X only)
// Ownership information
Uid uint32
Gid uint32
}
func (a *InodeAttributes) DebugString() string {
return fmt.Sprintf(
"%d %d %v %d %d",
a.Size,
a.Nlink,
a.Mode,
a.Uid,
a.Gid)
}
// GenerationNumber represents a generation of an inode. It is irrelevant for
// file systems that won't be exported over NFS. For those that will and that
// reuse inode IDs when they become free, the generation number must change
// when an ID is reused.
//
// This corresponds to struct inode::i_generation in the VFS layer.
// (https://tinyurl.com/23sr9svd)
//
// Some related reading:
//
// http://fuse.sourceforge.net/doxygen/structfuse__entry__param.html
// http://stackoverflow.com/q/11071996/1505451
// https://tinyurl.com/yn7wmcmy
// http://julipedia.meroh.net/2005/09/nfs-file-handles.html
// https://tinyurl.com/2c8vsfrs
type GenerationNumber uint64
// HandleID is an opaque 64-bit number used to identify a particular open
// handle to a file or directory.
//
// This corresponds to fuse_file_info::fh.
type HandleID uint64
// DirOffset is an offset into an open directory handle. This is opaque to
// FUSE, and can be used for whatever purpose the file system desires. See
// notes on ReadDirOp.Offset for details.
type DirOffset uint64
// ChildInodeEntry contains information about a child inode within its parent
// directory. It is shared by LookUpInodeOp, MkDirOp, CreateFileOp, etc, and is
// consumed by the kernel in order to set up a dcache entry.
type ChildInodeEntry struct {
// The ID of the child inode. The file system must ensure that the returned
// inode ID remains valid until a later ForgetInodeOp.
Child InodeID
// A generation number for this incarnation of the inode with the given ID.
// See comments on type GenerationNumber for more.
Generation GenerationNumber
// Current attributes for the child inode.
//
// When creating a new inode, the file system is responsible for initializing
// and recording (where supported) attributes like time information,
// ownership information, etc.
//
// Ownership information in particular must be set to something reasonable or
// by default root will own everything and unprivileged users won't be able
// to do anything useful. In traditional file systems in the kernel, the
// function inode_init_owner (https://tinyurl.com/5yfdrfdf) contains the
// standards-compliant logic for this.
Attributes InodeAttributes
// The FUSE VFS layer in the kernel maintains a cache of file attributes,
// used whenever up to date information about size, mode, etc. is needed.
//
// For example, this is the abridged call chain for fstat(2):
//
// * (https://tinyurl.com/bdd6ek3c) fstat calls vfs_fstat.
// * (https://tinyurl.com/3enne935) vfs_fstat eventuall calls
// vfs_getattr_nosec.
// * (https://tinyurl.com/y5rkhzx4) vfs_getattr_nosec calls i_op->getattr.
// * (https://tinyurl.com/33hawubc) fuse_getattr calls
// fuse_update_attributes.
// * (https://tinyurl.com/ywhhshxt) fuse_update_attributes uses the values
// in the struct inode if allowed, otherwise calling out to the
// user-space code.
//
// In addition to obvious cases like fstat, this is also used in more subtle
// cases like updating size information before seeking
// (https://tinyurl.com/hv2jabnh) or reading (https://tinyurl.com/bdkpz96v).
//
// Most 'real' file systems do not set inode_operations::getattr, and
// therefore vfs_getattr_nosec calls generic_fillattr which simply grabs the
// information from the inode struct. This makes sense because these file
// systems cannot spontaneously change; all modifications go through the
// kernel which can update the inode struct as appropriate.
//
// In contrast, a FUSE file system may have spontaneous changes, so it calls
// out to user space to fetch attributes. However this is expensive, so the
// FUSE layer in the kernel caches the attributes if requested.
//
// This field controls when the attributes returned in this response and
// stashed in the struct inode should be re-queried. Leave at the zero value
// to disable caching.
//
// More reading:
// http://stackoverflow.com/q/21540315/1505451
AttributesExpiration time.Time
// The time until which the kernel may maintain an entry for this name to
// inode mapping in its dentry cache. After this time, it will revalidate the
// dentry.
//
// As in the discussion of attribute caching above, unlike real file systems,
// FUSE file systems may spontaneously change their name -> inode mapping.
// Therefore the FUSE VFS layer uses dentry_operations::d_revalidate
// (https://tinyurl.com/ydb8ncrk) to intercept lookups and revalidate by
// calling the user-space LookUpInode method. However the latter may be slow,
// so it caches the entries until the time defined by this field.
//
// Example code walk:
//
// * (https://tinyurl.com/crddueft) lookup_dcache calls d_revalidate if
// enabled.
//
// * (https://tinyurl.com/bdsxacjy) fuse_dentry_revalidate just uses the
// dentry's inode if fuse_dentry_time(entry) hasn't passed. Otherwise
// it sends a lookup request.
//
// Leave at the zero value to disable caching.
//
// Beware: this value is ignored on OS X, where entry caching is disabled by
// default. See notes on MountConfig.EnableVnodeCaching for more.
EntryExpiration time.Time
}
|