1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /**
17  * @file unique_fd.h
18  *
19  * @brief Provides APIs to manage file descriptors (FDs) implemented in c_utils.
20  *
21  * The manager class `UniqueFdAddDeletor`,
22  * the default deleter class `DefaultDeleter`,
23  * and related global overloaded operator functions are provided.
24  */
25 #ifndef UNIQUE_FD_H
26 #define UNIQUE_FD_H
27 
28 #include <unistd.h>
29 
30 namespace OHOS {
31 
32 /**
33  * @brief Provides the default implementation for a deleter,
34  * including a static function to close FDs.
35  *
36  * The deleter is used for closing FDs. You can implement a deleter to
37  * deal with a different scenario. When `Deleter::Close()` is called to enable
38  * a `UniqueFdAddDeletor` object to release the management of an FD,
39  * the FD can no longer be taken over by other `UniqueFdAddDeletor` objects.
40  */
41 class DefaultDeleter {
42 public:
43     /**
44      * @brief Default function to close an FD.
45      *
46      * Call `close()` if the input FD is valid (greater than or equal to 0).
47      *
48      * @param fd Indicates an FD.
49      */
Close(int fd)50     static void Close(int fd)
51     {
52         if (fd >= 0) {
53             close(fd);
54         }
55     }
56 };
57 
58 template <typename Deleter>
59 class UniqueFdAddDeletor;
60 template <typename Deleter>
61 bool operator==(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
62 template <typename Deleter>
63 bool operator!=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
64 template <typename Deleter>
65 bool operator>=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
66 template <typename Deleter>
67 bool operator>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
68 template <typename Deleter>
69 bool operator<=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
70 template <typename Deleter>
71 bool operator<(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
72 
73 /**
74  * @brief Defines an FD manager.
75  *
76  * To ensure unique management on an FD, avoid the double-close issue,
77  * which may cause a file to be incorrectly closed./n
78  * The management of an FD can be delivered between `UniqueFdAddDeletor`
79  * objects. An FD will be closed if no `UniqueFdAddDeletor` object is available
80  * to take over its management.
81  *
82  * @tparam Deleter Indicates a deleter.
83  * @see DefaultDeleter
84  */
85 template <typename Deleter = DefaultDeleter>
86 class UniqueFdAddDeletor final {
87     friend bool operator==<Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
88 
89     friend bool operator!=<Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
90 
91     friend bool operator>=<Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
92 
93     friend bool operator><Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
94 
95     friend bool operator<=<Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
96 
97     friend bool operator< <Deleter>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs);
98 
99 public:
100     /**
101      * @brief Creates a `UniqueFdAddDeletor` object to manage an FD.
102      *
103      * @param value Indicates the FD to be managed.
104      */
UniqueFdAddDeletor(const int & value)105     explicit UniqueFdAddDeletor(const int& value)
106         : fd_(value)
107     {
108     }
109 
110     /**
111      * @brief Constructor used to create a `UniqueFdAddDeletor` object
112      * with the FD set to `-1`.
113      */
UniqueFdAddDeletor()114     UniqueFdAddDeletor()
115         : fd_(-1)
116     {
117     }
118 
119     /**
120      * @brief Destructor used to destroy this `UniqueFdAddDeletor` object.
121      *
122      * This function is used to close the FD and set the FD to `-1`.
123      */
~UniqueFdAddDeletor()124     ~UniqueFdAddDeletor() { Reset(-1); }
125 
126     /**
127      * @brief Releases the management on the current FD and sets it to `-1`.
128      *
129      * @return Returns the original FD before release.
130      * @note The released FD needs to be taken over by another
131      * `UniqueFdAddDeletor` object; otherwise, it must be closed manually.
132      */
Release()133     int Release()
134     {
135         int tmp = fd_;
136         fd_ = -1;
137         return tmp;
138     }
139 
140     // this is dangerous, when you use it , you should know it,
141     // do not operator on the ret
142     /**
143      * @brief An overloaded cast operator function.
144      *
145      * This function will be called when passing a `UniqueFdAddDeletor` object
146      * to a function that requires a parameter of `int`.
147      *
148      * @return Returns the current FD under management.
149      */
150     operator int() const { return Get(); } // NOLINT
151 
152     // this is dangerous, when you use it , you should know it, do not operator
153     // on the ret
154     /**
155      * @brief Obtains the current FD under management, without releasing it.
156      *
157      * @return Returns the current FD.
158      */
Get()159     int Get() const
160     {
161         return fd_;
162     }
163 
164     // we need move fd from one to another
165     /**
166      * @brief Move constructor used to deliver the management of an FD from a
167      * `UniqueFdAddDeletor` object to this object.
168      *
169      * @param rhs Indicates the source `UniqueFdAddDeletor` object.
170      */
UniqueFdAddDeletor(UniqueFdAddDeletor && rhs)171     UniqueFdAddDeletor(UniqueFdAddDeletor&& rhs)
172     {
173         int rhsfd = rhs.Release();
174         fd_ = rhsfd;
175     }
176 
177     /**
178      * @brief Overloaded move assignment operator function used to deliver the
179      * management of an FD from a `UniqueFdAddDeletor` object to this object.
180      *
181      * @param rhs Indicates the source `UniqueFdAddDeletor` object.
182      * @return Returns this `UniqueFdAddDeletor` object.
183      * @note The current FD manged by this `UniqueFdAddDeletor` object will be
184      * closed, and this object will take over
185      * the FD originally managed by `rhs`.
186      */
187     UniqueFdAddDeletor& operator=(UniqueFdAddDeletor&& rhs)
188     {
189         int rhsfd = rhs.Release();
190         Reset(rhsfd);
191         return *this;
192     }
193 
194     /**
195      * @brief Checks whether the FD managed by this object and that managed by
196      * the source object are equal.
197      *
198      * @param rhs Indicates the source `UniqueFdAddDeletor` object.
199      *
200      * @return Returns `true` if the two FDs are equal; returns `false`
201      * otherwise.
202      */
203     bool operator==(const int& rhs) const
204     {
205         return fd_ == rhs;
206     }
207 
208     /**
209      * @brief Checks whether the FD managed by this object and that managed by
210      * the source object are not equal.
211      *
212      * @param rhs Indicates the source `UniqueFdAddDeletor` object.
213      *
214      * @return Returns `true` if the two FDs are not equal; returns `false`
215      * otherwise.
216      */
217     bool operator!=(const int& rhs) const
218     {
219         return !(fd_ == rhs);
220     }
221 
222     /**
223      * @brief Checks whether the FD managed by this object is greater than or
224      * equal to that managed by the source object.
225      *
226      * @param rhs Indicates the source `UniqueFdAddDeletor` object.
227      *
228      * @return Returns `true` if FD managed by this object is greater than or
229      * equal to that managed by the source object; returns `false` otherwise.
230      */
231     bool operator>=(const int& rhs) const
232     {
233         return fd_ >= rhs;
234     }
235 
236     /**
237      * @brief Checks whether the FD managed by this object is greater than that
238      * managed by the source object.
239      *
240      * @param rhs Indicates the source `UniqueFdAddDeletor` object.
241      *
242      * @return Returns `true` if FD managed by this object is greater than that
243      * managed by the source object; returns `false` otherwise.
244      */
245     bool operator>(const int& rhs) const
246     {
247         return fd_ > rhs;
248     }
249 
250     /**
251      * @brief Checks whether the FD managed by this object is less than or equal
252      * to that managed by the source object.
253      *
254      * @param rhs Indicates the source `UniqueFdAddDeletor` object.
255      *
256      * @return Returns `true` if FD managed by this object is less than or equal
257      * to that managed by the source object; returns `false` otherwise.
258      */
259     bool operator<=(const int& rhs) const
260     {
261         return fd_ <= rhs;
262     }
263 
264     /**
265      * @brief Checks whether the FD managed by this object is less than that
266      * managed by the source object.
267      *
268      * @param rhs Indicates the source `UniqueFdAddDeletor` object.
269      *
270      * @return Returns `true` if FD managed by this object is less than that
271      * managed by the source object; returns `false` otherwise.
272      */
273     bool operator<(const int& rhs) const
274     {
275         return fd_ < rhs;
276     }
277 
278 private:
279     int fd_ = -1;
280 
Reset(int newValue)281     void Reset(int newValue)
282     {
283         if (fd_ >= 0) {
284             Deleter::Close(fd_);
285         }
286         fd_ = newValue;
287     }
288 
289     // disallow copy ctor and copy assign
290     UniqueFdAddDeletor(const UniqueFdAddDeletor& rhs) = delete;
291     UniqueFdAddDeletor& operator=(const UniqueFdAddDeletor& rhs) = delete;
292 };
293 
294 /**
295 * @brief Checks whether the FD managed by two objects (specified by `lhs` and
296 * `rhs` respectively) are equal.
297 *
298  * @tparam Deleter Indicates a deleter.
299  * @param lhs Indicates the first `UniqueFdAddDeletor` object.
300  * @param rhs Indicates the second `UniqueFdAddDeletor` object.
301  *
302  * @return Returns `true` if the two FDs are equal; returns `false` otherwise.
303  * @see DefaultDeleter
304  */
305 template <typename Deleter = DefaultDeleter>
306 bool operator==(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
307 {
308     return lhs == rhs.fd_;
309 }
310 
311 /**
312 * @brief Checks whether the FD managed by two objects (specified by `lhs` and
313 * `rhs` respectively) are not equal.
314 *
315  * @tparam Deleter Indicates a deleter.
316  * @param lhs Indicates the first `UniqueFdAddDeletor` object.
317  * @param rhs Indicates the second `UniqueFdAddDeletor` object.
318  *
319  * @return Returns `true` if the two FDs are not equal; returns `false`
320  * otherwise.
321  * @see DefaultDeleter
322  */
323 template <typename Deleter = DefaultDeleter>
324 bool operator!=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
325 {
326     return !(lhs == rhs.fd_);
327 }
328 
329 /**
330  * @brief Checks whether the FD managed by `lhs` is greater than or equal to
331  * that managed by `rhs`.
332  *
333  * @tparam Deleter Indicates a deleter.
334  * @param lhs Indicates the first `UniqueFdAddDeletor` object.
335  * @param rhs Indicates the second `UniqueFdAddDeletor` object.
336  *
337  * @return Returns `true` if the FD managed by `lhs` is greater than or equal to
338  * that managed by `rhs`; returns `false` otherwise.
339  * @see DefaultDeleter
340  */
341 template <typename Deleter = DefaultDeleter>
342 bool operator>=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
343 {
344     return lhs >= rhs.fd_;
345 }
346 
347 /**
348  * @brief Checks whether the FD managed by `lhs` is greater than that
349  * managed by `rhs`.
350  *
351  * @tparam Deleter Indicates a deleter.
352  * @param lhs Indicates the first `UniqueFdAddDeletor` object.
353  * @param rhs Indicates the second `UniqueFdAddDeletor` object.
354  *
355  * @return Returns `true` if the FD managed by `lhs` is greater than that
356  * managed by `rhs`; returns `false` otherwise.
357  * @see DefaultDeleter
358  */
359 template <typename Deleter = DefaultDeleter>
360 bool operator>(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
361 {
362     return lhs > rhs.fd_;
363 }
364 
365 /**
366  * @brief Checks whether the FD managed by `lhs` is less than or equal to that
367  * managed by `rhs`.
368  *
369  * @tparam Deleter Indicates a deleter.
370  * @param lhs Indicates the first `UniqueFdAddDeletor` object.
371  * @param rhs Indicates the second `UniqueFdAddDeletor` object.
372  *
373  * @return Returns `true` if the FD managed by `lhs` is less than or equal to
374  * that managed by `rhs`; returns `false` otherwise.
375  * @see DefaultDeleter
376  */
377 template <typename Deleter = DefaultDeleter>
378 bool operator<=(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
379 {
380     return lhs <= rhs.fd_;
381 }
382 
383 /**
384  * @brief Checks whether the FD managed by `lhs` is less than that
385  * managed by `rhs`.
386  *
387  * @tparam Deleter Indicates a deleter.
388  * @param lhs Indicates the first `UniqueFdAddDeletor` object.
389  * @param rhs Indicates the second `UniqueFdAddDeletor` object.
390  *
391  * @return Returns `true` if the FD managed by `lhs` is less than that
392  * managed by `rhs`; returns `false` otherwise.
393  * @see DefaultDeleter
394  */
395 template <typename Deleter = DefaultDeleter>
396 bool operator<(const int& lhs, const UniqueFdAddDeletor<Deleter>& rhs)
397 {
398     return lhs < rhs.fd_;
399 }
400 
401 using UniqueFd = UniqueFdAddDeletor<DefaultDeleter>;
402 } // namespace OHOS
403 #endif
404