Adding useful error message for 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/Format.h"
19 #include "folly/ScopeGuard.h"
20
21 #include <system_error>
22
23 #include <glog/logging.h>
24
25 namespace folly {
26
27 File::File()
28   : fd_(-1)
29   , ownsFd_(false)
30 {}
31
32 File::File(int fd, bool ownsFd)
33   : fd_(fd)
34   , ownsFd_(ownsFd)
35 {}
36
37 File::File(const char* name, int flags, mode_t mode)
38   : fd_(::open(name, flags, mode))
39   , ownsFd_(false) {
40
41   if (fd_ < 0) {
42     throw std::system_error(errno, std::system_category(),
43                             folly::format("open(\"{}\", {:#o}, 0{:#o}) failed",
44                                           name, flags, mode).str());
45   }
46   ownsFd_ = true;
47 }
48
49 File::File(File&& other)
50   : fd_(other.fd_)
51   , ownsFd_(other.ownsFd_) {
52
53   other.release();
54 }
55
56 File& File::operator=(File&& other) {
57   closeNoThrow();
58   swap(other);
59   return *this;
60 }
61
62 File::~File() {
63   closeNoThrow();  // ignore error
64 }
65
66 /* static */ File File::temporary() {
67   // make a temp file with tmpfile(), dup the fd, then return it in a File.
68   FILE* tmpFile = tmpfile();
69   if (!tmpFile) {
70     throw std::system_error(errno, std::system_category(), "tmpfile() failed");
71   }
72   SCOPE_EXIT { fclose(tmpFile); };
73
74   int fd = dup(fileno(tmpFile));
75   if (fd < 0) {
76     throw std::system_error(errno, std::system_category(), "dup() failed");
77   }
78
79   return File(fd, true);
80 }
81
82 void File::release() {
83   fd_ = -1;
84   ownsFd_ = false;
85 }
86
87 void File::swap(File& other) {
88   using std::swap;
89   swap(fd_, other.fd_);
90   swap(ownsFd_, other.ownsFd_);
91 }
92
93 void swap(File& a, File& b) {
94   a.swap(b);
95 }
96
97 void File::close() {
98   if (!closeNoThrow()) {
99     throw std::system_error(errno, std::system_category(), "close() failed");
100   }
101 }
102
103 bool File::closeNoThrow() {
104   int r = ownsFd_ ? ::close(fd_) : 0;
105   release();
106   return r == 0;
107 }
108
109 }  // namespace folly