1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/types.h>
11 
12 #include <fbl/function.h>
13 #include <fbl/intrusive_double_list.h>
14 #include <fbl/macros.h>
15 #include <fbl/ref_counted_internal.h>
16 #include <fbl/ref_ptr.h>
17 #include <fs/ref_counted.h>
18 #include <fs/vfs.h>
19 #include <lib/fdio/io.h>
20 #include <lib/fdio/vfs.h>
21 #include <zircon/assert.h>
22 #include <zircon/compiler.h>
23 #include <zircon/types.h>
24 
25 #include <utility>
26 
27 #ifdef __Fuchsia__
28 #include <fuchsia/io/c/fidl.h>
29 #include <lib/zx/channel.h>
30 
31 #include <utility>
32 #endif // __Fuchsia__
33 
34 namespace fs {
35 
vfs_valid_name(fbl::StringPiece name)36 inline bool vfs_valid_name(fbl::StringPiece name) {
37     return name.length() <= NAME_MAX &&
38            memchr(name.data(), '/', name.length()) == nullptr &&
39            name != "." && name != "..";
40 }
41 
42 // The VFS interface declares a default abstract Vnode class with
43 // common operations that may be overwritten.
44 //
45 // The ops are used for dispatch and the lifecycle of Vnodes are owned
46 // by RefPtrs.
47 //
48 // All names passed to the Vnode class are valid according to "vfs_valid_name".
49 //
50 // The lower half of flags (VFS_FLAG_RESERVED_MASK) is reserved
51 // for usage by fs::Vnode, but the upper half of flags may
52 // be used by subclasses of Vnode.
53 class Vnode : public VnodeRefCounted<Vnode>, public fbl::Recyclable<Vnode> {
54 public:
55     virtual ~Vnode();
fbl_recycle()56     virtual void fbl_recycle() { delete this; }
57 
58     // Ensures that it is valid to access the vnode with given flags.
59     virtual zx_status_t ValidateFlags(uint32_t flags);
60 
61     // Provides an opportunity to redirect subsequent I/O operations to a
62     // different vnode.
63     //
64     // Flags will have already been validated by "ValidateFlags".
65     // Open should never be invoked if flags includes "O_PATH".
66     //
67     // If the implementation of |Open()| sets |out_redirect| to a non-null value.
68     // all following I/O operations on the opened file will be redirected to the
69     // indicated vnode instead of being handled by this instance.
70     //
71     // |flags| are the open flags to be validated, such as |ZX_FS_RIGHT_READABLE| and
72     // |ZX_FS_FLAG_DIRECTORY|.
73     virtual zx_status_t Open(uint32_t flags, fbl::RefPtr<Vnode>* out_redirect);
74 
75     // METHODS FOR OPENED NODES
76     //
77     // The following operations will not be invoked unless the Vnode has
78     // been "Open()"-ed successfully.
79     //
80     // For files opened with O_PATH (as a file descriptor only) the base
81     // classes' implementation of some of these functions may be invoked anyway.
82 
83 #ifdef __Fuchsia__
84     // Serves a connection to the Vnode over the specified channel.
85     //
86     // The default implementation creates and registers an RIO |Connection| with the VFS.
87     // Subclasses may override this behavior to serve custom protocols over the channel.
88     //
89     // |vfs| is the VFS which manages the Vnode.
90     // |channel| is the channel over which the client will exchange messages with the Vnode.
91     // |flags| are the flags which were previously provided to |Open()|.
92     virtual zx_status_t Serve(fs::Vfs* vfs, zx::channel channel, uint32_t flags);
93 
94     // Extract handle, type, and extra info from a vnode.
95     virtual zx_status_t GetHandles(uint32_t flags, fuchsia_io_NodeInfo* info);
96 
97     virtual zx_status_t WatchDir(Vfs* vfs, uint32_t mask, uint32_t options, zx::channel watcher);
98 #endif
99 
100     // Closes vn. Will be called once for each successful Open().
101     //
102     // Typically, most Vnodes simply return "ZX_OK".
103     virtual zx_status_t Close();
104 
105     // Read data from vn at offset.
106     //
107     // If successful, returns the number of bytes read in |out_actual|. This must be
108     // less than or equal to |len|.
109     virtual zx_status_t Read(void* data, size_t len, size_t off, size_t* out_actual);
110 
111     // Write |len| bytes of |data| to the file, starting at |offset|.
112     //
113     // If successful, returns the number of bytes written in |out_actual|. This must be
114     // less than or equal to |len|.
115     virtual zx_status_t Write(const void* data, size_t len, size_t offset,
116                               size_t* out_actual);
117 
118     // Write |len| bytes of |data| to the end of the file.
119     //
120     // If successful, returns the number of bytes written in |out_actual|, and
121     // returns the new end of file offset in |out_end|.
122     virtual zx_status_t Append(const void* data, size_t len, size_t* out_end,
123                                size_t* out_actual);
124 
125     // Change the size of vn
126     virtual zx_status_t Truncate(size_t len);
127 
128     // Set attributes of vn.
129     virtual zx_status_t Setattr(const vnattr_t* a);
130 
131     // Acquire a vmo from a vnode.
132     //
133     // At the moment, mmap can only map files from read-only filesystems,
134     // since (without paging) there is no mechanism to update either
135     // 1) The file by writing to the mapping, or
136     // 2) The mapping by writing to the underlying file.
137     virtual zx_status_t GetVmo(int flags, zx_handle_t* out);
138 
139     // Syncs the vnode with its underlying storage.
140     //
141     // Returns the result status through a closure.
142     using SyncCallback = fbl::Function<void(zx_status_t status)>;
143     virtual void Sync(SyncCallback closure);
144 
145     // Read directory entries of vn, error if not a directory.
146     // FS-specific Cookie must be a buffer of vdircookie_t size or smaller.
147     // Cookie must be zero'd before first call and will be used by
148     // the readdir implementation to maintain state across calls.
149     // To "rewind" and start from the beginning, cookie may be zero'd.
150     virtual zx_status_t Readdir(vdircookie_t* cookie, void* dirents, size_t len,
151                                 size_t* out_actual);
152 
153     // METHODS FOR OPENED OR UNOPENED NODES
154     //
155     // The following operations may be invoked on a Vnode, even if it has
156     // not been "Open()"-ed.
157 
158     // Attempt to find child of vn, child returned on success.
159     // Name is len bytes long, and does not include a null terminator.
160     virtual zx_status_t Lookup(fbl::RefPtr<Vnode>* out, fbl::StringPiece name);
161 
162     // Read attributes of vn.
163     virtual zx_status_t Getattr(vnattr_t* a);
164 
165     // Create a new node under vn.
166     // Name is len bytes long, and does not include a null terminator.
167     // Mode specifies the type of entity to create.
168     virtual zx_status_t Create(fbl::RefPtr<Vnode>* out, fbl::StringPiece name, uint32_t mode);
169 
170     // Removes name from directory vn
171     virtual zx_status_t Unlink(fbl::StringPiece name, bool must_be_dir);
172 
173     // Renames the path at oldname in olddir to the path at newname in newdir.
174     // Called on the "olddir" vnode.
175     // Unlinks any prior newname if it already exists.
176     virtual zx_status_t Rename(fbl::RefPtr<Vnode> newdir,
177                                fbl::StringPiece oldname, fbl::StringPiece newname,
178                                bool src_must_be_dir, bool dst_must_be_dir);
179 
180     // Creates a hard link to the 'target' vnode with a provided name in vndir
181     virtual zx_status_t Link(fbl::StringPiece name, fbl::RefPtr<Vnode> target);
182 
183     // Invoked by the VFS layer whenever files are added or removed.
184     virtual void Notify(fbl::StringPiece name, unsigned event);
185 
186 #ifdef __Fuchsia__
187     // Return information about the underlying filesystem, if desired.
188     virtual zx_status_t QueryFilesystem(fuchsia_io_FilesystemInfo* out);
189 
190     // Returns the name of the device backing the filesystem, if one exists.
191     virtual zx_status_t GetDevicePath(size_t buffer_len, char* out_name, size_t* out_len);
192 
193     // Attaches a handle to the vnode, if possible. Otherwise, returns an error.
194     virtual zx_status_t AttachRemote(MountChannel h);
195 
196     // The following methods are required to mount sub-filesystems. The logic
197     // (and storage) necessary to implement these functions exists within the
198     // "RemoteContainer" class, which may be composed inside Vnodes that wish
199     // to act as mount points.
200 
201     // The vnode is acting as a mount point for a remote filesystem or device.
202     virtual bool IsRemote() const;
203     virtual zx::channel DetachRemote();
204     virtual zx_handle_t GetRemote() const;
205     virtual void SetRemote(zx::channel remote);
206 
207 #endif
208 
209 protected:
210     DISALLOW_COPY_ASSIGN_AND_MOVE(Vnode);
211     Vnode();
212 };
213 
214 // Opens a vnode by reference.
215 // The |vnode| reference is updated in-place if redirection occurs.
OpenVnode(uint32_t flags,fbl::RefPtr<Vnode> * vnode)216 inline zx_status_t OpenVnode(uint32_t flags, fbl::RefPtr<Vnode>* vnode) {
217     fbl::RefPtr<Vnode> redirect;
218     zx_status_t status = (*vnode)->Open(flags, &redirect);
219     if (status == ZX_OK && redirect != nullptr) {
220         *vnode = std::move(redirect);
221     }
222     return status;
223 }
224 
225 // Helper class used to fill direntries during calls to Readdir.
226 class DirentFiller {
227 public:
228     DISALLOW_COPY_ASSIGN_AND_MOVE(DirentFiller);
229 
230     DirentFiller(void* ptr, size_t len);
231 
232     // Attempts to add the name to the end of the dirent buffer
233     // which is returned by readdir.
234     zx_status_t Next(fbl::StringPiece name, uint8_t type, uint64_t ino);
235 
BytesFilled()236     zx_status_t BytesFilled() const {
237         return static_cast<zx_status_t>(pos_);
238     }
239 
240 private:
241     char* ptr_;
242     size_t pos_;
243     const size_t len_;
244 };
245 
246 } // namespace fs
247