folly/{experimental => .}/File
[folly.git] / folly / File.cpp
1 /*
2  * Copyright 2013 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "folly/File.h"
18 #include "folly/ScopeGuard.h"
19
20 #include <system_error>
21
22 #include <glog/logging.h>
23
24 namespace folly {
25
26 File::File()
27   : fd_(-1)
28   , ownsFd_(false)
29 {}
30
31 File::File(int fd, bool ownsFd)
32   : fd_(fd)
33   , ownsFd_(ownsFd)
34 {}
35
36 File::File(const char* name, int flags, mode_t mode)
37   : fd_(::open(name, flags, mode))
38   , ownsFd_(false) {
39
40   if (fd_ < 0) {
41     throw std::system_error(errno, std::system_category(), "open() failed");
42   }
43   ownsFd_ = true;
44 }
45
46 File::File(File&& other)
47   : fd_(other.fd_)
48   , ownsFd_(other.ownsFd_) {
49
50   other.release();
51 }
52
53 File& File::operator=(File&& other) {
54   closeNoThrow();
55   swap(other);
56   return *this;
57 }
58
59 File::~File() {
60   closeNoThrow();  // ignore error
61 }
62
63 /* static */ File File::temporary() {
64   // make a temp file with tmpfile(), dup the fd, then return it in a File.
65   FILE* tmpFile = tmpfile();
66   if (!tmpFile) {
67     throw std::system_error(errno, std::system_category(), "tmpfile() failed");
68   }
69   SCOPE_EXIT { fclose(tmpFile); };
70
71   int fd = dup(fileno(tmpFile));
72   if (fd < 0) {
73     throw std::system_error(errno, std::system_category(), "dup() failed");
74   }
75
76   return File(fd, true);
77 }
78
79 void File::release() {
80   fd_ = -1;
81   ownsFd_ = false;
82 }
83
84 void File::swap(File& other) {
85   using std::swap;
86   swap(fd_, other.fd_);
87   swap(ownsFd_, other.ownsFd_);
88 }
89
90 void swap(File& a, File& b) {
91   a.swap(b);
92 }
93
94 void File::close() {
95   if (!closeNoThrow()) {
96     throw std::system_error(errno, std::system_category(), "close() failed");
97   }
98 }
99
100 bool File::closeNoThrow() {
101   int r = ownsFd_ ? ::close(fd_) : 0;
102   release();
103   return r == 0;
104 }
105
106 }  // namespace folly