xref: /aosp_15_r20/external/libbrillo/brillo/streams/file_stream.h (revision 1a96fba65179ea7d3f56207137718607415c5953)
1 // Copyright 2015 The Chromium OS 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 #ifndef LIBBRILLO_BRILLO_STREAMS_FILE_STREAM_H_
6 #define LIBBRILLO_BRILLO_STREAMS_FILE_STREAM_H_
7 
8 #include <sys/types.h>
9 
10 #include <memory>
11 
12 #include <base/files/file_path.h>
13 #include <base/macros.h>
14 #include <brillo/brillo_export.h>
15 #include <brillo/streams/stream.h>
16 
17 namespace brillo {
18 
19 // FileStream class provides the implementation of brillo::Stream for files
20 // and file-descriptor-based streams, such as pipes and sockets.
21 // The FileStream class cannot be instantiated by clients directly. However
22 // they should use the static factory methods such as:
23 //  - FileStream::Open(): to open a file by name.
24 //  - FileStream::CreateTemporary(): to create a temporary file stream.
25 //  - FileStream::FromFileDescriptor(): to create a stream using an existing
26 //    file descriptor.
27 class BRILLO_EXPORT FileStream : public Stream {
28  public:
29   // See comments for FileStream::Open() for detailed description of this enum.
30   enum class Disposition {
31     OPEN_EXISTING,  // Open existing file only. Fail if doesn't exist.
32     CREATE_ALWAYS,  // Create empty file, possibly overwriting existing file.
33     CREATE_NEW_ONLY,  // Create new file if doesn't exist already.
34     TRUNCATE_EXISTING,  // Open/truncate existing file. Fail if doesn't exist.
35   };
36 
37   // Simple interface to wrap native library calls so that they can be mocked
38   // out for testing.
39   struct FileDescriptorInterface {
40     using DataCallback = base::Callback<void(Stream::AccessMode)>;
41 
42     virtual ~FileDescriptorInterface() = default;
43 
44     virtual bool IsOpen() const = 0;
45     virtual ssize_t Read(void* buf, size_t nbyte) = 0;
46     virtual ssize_t Write(const void* buf, size_t nbyte) = 0;
47     virtual off64_t Seek(off64_t offset, int whence) = 0;
48     virtual mode_t GetFileMode() const = 0;
49     virtual uint64_t GetSize() const = 0;
50     virtual int Truncate(off64_t length) const = 0;
51     virtual int Close() = 0;
52     virtual bool WaitForData(AccessMode mode,
53                              const DataCallback& data_callback,
54                              ErrorPtr* error) = 0;
55     virtual int WaitForDataBlocking(AccessMode in_mode,
56                                     base::TimeDelta timeout,
57                                     AccessMode* out_mode) = 0;
58     virtual void CancelPendingAsyncOperations() = 0;
59   };
60 
61   // == Construction ==========================================================
62 
63   // Opens a file at specified |path| for reading, writing or both as indicated
64   // by |mode|. The |disposition| specifies how the file must be opened/created:
65   //  - OPEN_EXISTING   - opens the existing file and keeps its content intact.
66   //                      The seek pointer is at the beginning of the file.
67   //  - CREATE_ALWAYS   - creates the file always. If it exists, the file is
68   //                      truncated.
69   //  - CREATE_NEW_ONLY - creates a new file only if it doesn't exist. Fails
70   //                      otherwise. This can be useful for creating lock files.
71   //  - TRUNCATE_EXISTING - opens existing file and truncates it to zero length.
72   //                       Fails if the file doesn't already exist.
73   // If successful, the open file stream is returned. Otherwise returns the
74   // stream pointer containing nullptr and fills in the details of the error
75   // in |error| object, if provided.
76   static StreamPtr Open(const base::FilePath& path,
77                         AccessMode mode,
78                         Disposition disposition,
79                         ErrorPtr* error);
80 
81   // Creates a temporary unnamed file and returns a stream to it. The file will
82   // be deleted when the stream is destroyed.
83   static StreamPtr CreateTemporary(ErrorPtr* error);
84 
85   // Creates a file stream based on existing file descriptor. The file
86   // descriptor will be set into non-blocking mode and will be owned by the
87   // resulting stream (and closed when the stream is destroyed).
88   // If the function fails, returns a null stream pointer and sets the error
89   // details to |error| object. Also note that it is the caller's responsibility
90   // to close the file descriptor if this function fails, since the stream
91   // hasn't been created yet and didn't take ownership of the file descriptor.
92   // |own_descriptor| indicates whether the stream must close the underlying
93   // file descriptor when its CloseBlocking() method is called. This should be
94   // set to false for file descriptors that shouldn't be closed (e.g. stdin).
95   static StreamPtr FromFileDescriptor(int file_descriptor,
96                                       bool own_descriptor,
97                                       ErrorPtr* error);
98 
99   // == Stream capabilities ===================================================
100   bool IsOpen() const override;
101   bool CanRead() const override;
102   bool CanWrite() const override;
103   bool CanSeek() const override;
104   bool CanGetSize() const override;
105 
106   // == Stream size operations ================================================
107   uint64_t GetSize() const override;
108   bool SetSizeBlocking(uint64_t size, ErrorPtr* error) override;
109   uint64_t GetRemainingSize() const override;
110 
111   // == Seek operations =======================================================
112   uint64_t GetPosition() const override;
113   bool Seek(int64_t offset,
114             Whence whence,
115             uint64_t* new_position,
116             ErrorPtr* error) override;
117 
118   // == Read operations =======================================================
119   bool ReadNonBlocking(void* buffer,
120                        size_t size_to_read,
121                        size_t* size_read,
122                        bool* end_of_stream,
123                        ErrorPtr* error) override;
124 
125   // == Write operations ======================================================
126   bool WriteNonBlocking(const void* buffer,
127                         size_t size_to_write,
128                         size_t* size_written,
129                         ErrorPtr* error) override;
130 
131   // == Finalizing/closing streams  ===========================================
132   bool FlushBlocking(ErrorPtr* error) override;
133   bool CloseBlocking(ErrorPtr* error) override;
134 
135   // == Data availability monitoring ==========================================
136 
137   // Override for Stream::WaitForData to start watching the associated file
138   // descriptor for non-blocking read/write operations.
139   bool WaitForData(AccessMode mode,
140                    const base::Callback<void(AccessMode)>& callback,
141                    ErrorPtr* error) override;
142 
143   // Runs select() on the file descriptor to wait until we can do non-blocking
144   // I/O on it.
145   bool WaitForDataBlocking(AccessMode in_mode,
146                            base::TimeDelta timeout,
147                            AccessMode* out_mode,
148                            ErrorPtr* error) override;
149 
150   // Cancels pending asynchronous read/write operations.
151   void CancelPendingAsyncOperations() override;
152 
153  private:
154   friend class FileStreamTest;
155 
156   // Internal constructor used by the factory methods Open(), CreateTemporary(),
157   // and FromFileDescriptor().
158   FileStream(std::unique_ptr<FileDescriptorInterface> fd_interface,
159              AccessMode mode);
160 
161   // Wrapper for the file descriptor. Used in testing to mock out the real
162   // file system APIs.
163   std::unique_ptr<FileDescriptorInterface> fd_interface_;
164 
165   // The access mode this stream is open with.
166   AccessMode access_mode_{AccessMode::READ_WRITE};
167 
168   // Set to false for streams that are guaranteed non-seekable.
169   bool seekable_{true};
170 
171   // Set to false for streams that have unknown size.
172   bool can_get_size_{false};
173 
174   DISALLOW_COPY_AND_ASSIGN(FileStream);
175 };
176 
177 }  // namespace brillo
178 
179 #endif  // LIBBRILLO_BRILLO_STREAMS_FILE_STREAM_H_
180