blob: db02741eff2505cd0446dd6efc7ddff4da719da7 [file] [log] [blame]
Loganef9e4f72011-01-06 03:18:12 +08001/*
2 * Copyright 2010, The Android Open Source Project
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#define LOG_TAG "bcc"
18#include <cutils/log.h>
19
20#include "FileHandle.h"
21
22#include <errno.h>
23#include <fcntl.h>
24#include <sys/file.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <unistd.h>
28
29#include <string.h>
30
31namespace bcc {
32
33int FileHandle::open(char const *filename, OpenMode::ModeType mode) {
34 static int const open_flags[2] = {
35 O_RDONLY,
36 O_RDWR | O_CREAT | O_TRUNC,
37 };
38
39 static int const lock_flags[2] = { LOCK_SH, LOCK_EX };
40
41 static char const *const open_mode_str[2] = { "read", "write" };
42
43 static size_t const RETRY_MAX = 4;
44
45 static useconds_t const RETRY_USEC = 200000UL;
46
47 for (size_t i = 0; i < RETRY_MAX; ++i) {
48 // Try to open the file
49 mFD = ::open(filename, open_flags[mode], 0644);
50
51 if (mFD < 0) {
52 if (errno == EINTR) {
53 // Interrupt occurs while opening the file. Retry.
54 continue;
55 }
56
57 LOGE("Unable to open %s in %s mode. (reason: %s)\n",
58 filename, open_mode_str[mode], strerror(errno));
59
60 return -1;
61 }
62
63 // Try to lock the file
64 if (flock(mFD, lock_flags[mode] | LOCK_NB) < 0) {
65 LOGW("Unable to acquire the lock immediately, block and wait now ...\n");
66
67 if (flock(mFD, lock_flags[mode]) < 0) {
68 LOGE("Unable to acquire the lock. Retry ...\n");
69
70 ::close(mFD);
71 mFD = -1;
72
73 usleep(RETRY_USEC);
74 continue;
75 }
76 }
77
78 // Note: From now on, the object is correctly initialized. We have to
79 // use this->close() to close the file now.
80
81 // Check rather we have locked the correct file or not
82 struct stat sfd, sfname;
83
84 if (fstat(mFD, &sfd) == -1 || stat(filename, &sfname) == -1 ||
85 sfd.st_dev != sfname.st_dev || sfd.st_ino != sfname.st_ino) {
86 // The file we locked is different from the given path. This may
87 // occur when someone changes the file node before we lock the file.
88 // Just close the file, and retry after sleeping.
89
90 this->close();
91 usleep(RETRY_USEC);
92 continue;
93 }
94
95 // Good, we have open and lock the file correctly.
Logan269df462011-01-07 12:51:48 +080096 LOGI("File opened. fd=%d\n", mFD);
Loganef9e4f72011-01-06 03:18:12 +080097 return mFD;
98 }
99
100 LOGE("Unable to open %s in %s mode.\n", filename, open_mode_str[mode]);
101 return -1;
102}
103
104
105void FileHandle::close() {
106 if (mFD >= 0) {
Loganef9e4f72011-01-06 03:18:12 +0800107 flock(mFD, LOCK_UN);
Logan269df462011-01-07 12:51:48 +0800108 ::close(mFD);
109 LOGI("File closed. fd=%d\n", mFD);
Loganef9e4f72011-01-06 03:18:12 +0800110 mFD = -1;
111 }
112}
113
114
115ssize_t FileHandle::read(char *buf, size_t count) {
116 if (mFD < 0) {
117 return -1;
118 }
119
120 while (true) {
121 ssize_t nread = ::read(mFD, static_cast<void *>(buf), count);
122
123 if (nread >= 0) {
124 return nread;
125 }
126
127 if (errno != EAGAIN && errno != EINTR) {
128 // If the errno is EAGAIN or EINTR, then we try to read again.
129 // Otherwise, consider this is a failure. And returns zero.
130 return -1;
131 }
132 }
133
134 // Unreachable
135 return -1;
136}
137
138
139ssize_t FileHandle::write(char const *buf, size_t count) {
140 if (mFD < 0) {
141 return -1;
142 }
143
144 ssize_t written = 0;
145
146 while (count > 0) {
147 ssize_t nwrite = ::write(mFD, static_cast<void const *>(buf), count);
148
149 if (nwrite < 0) {
150 if (errno != EAGAIN && errno != EINTR) {
151 return written;
152 }
153
154 continue;
155 }
Shih-wei Liaof7cfc022011-01-07 06:39:53 -0800156
Loganef9e4f72011-01-06 03:18:12 +0800157 written += nwrite;
158 count -= (size_t)nwrite;
159 buf += (size_t)nwrite;
160 }
161
162 return written;
163}
164
165
166off_t FileHandle::seek(off_t offset, int whence) {
167 return (mFD < 0) ? -1 : lseek(mFD, offset, whence);
168}
169
170
171void FileHandle::truncate() {
172 if (mFD >= 0) {
Logancc6da3f2011-01-07 10:45:52 +0800173 if (ftruncate(mFD, 0) != 0) {
174 LOGE("Unable to truncate the file.\n");
175 }
Loganef9e4f72011-01-06 03:18:12 +0800176 }
177}
178
179
180} // namespace bcc