1// FDManager.cpp
2
3#include <new>
4
5#include <dirent.h>
6#include <errno.h>
7#include <fcntl.h>
8
9#include <Directory.h>
10#include <Entry.h>
11#include <File.h>
12#include <fs_attr.h>
13
14#include "AutoLocker.h"
15#include "FDManager.h"
16
17// FD constants
18static const int32 kDefaultFDLimit = 512;
19static const int32 kFDLimitIncrement = 128;
20
21// private BeOS syscall to set the FD limit
22extern "C" int _kset_fd_limit_(int num);
23
24// constructor
25FDManager::FDManager()
26	: fLock("FD manager"),
27	  fFDLimit(kDefaultFDLimit)
28{
29}
30
31// destructor
32FDManager::~FDManager()
33{
34}
35
36// Init
37status_t
38FDManager::Init()
39{
40	return _kset_fd_limit_(fFDLimit);
41}
42
43// CreateDefault
44status_t
45FDManager::CreateDefault()
46{
47	if (sManager)
48		return B_OK;
49
50	FDManager* manager = new(nothrow) FDManager;
51	if (!manager)
52		return B_NO_MEMORY;
53
54	status_t error = manager->Init();
55	if (error != B_OK) {
56		delete manager;
57		return error;
58	}
59
60	sManager = manager;
61	return B_OK;
62}
63
64// DeleteDefault
65void
66FDManager::DeleteDefault()
67{
68	if (sManager) {
69		delete sManager;
70		sManager = NULL;
71	}
72}
73
74// GetDefault
75FDManager*
76FDManager::GetDefault()
77{
78	return sManager;
79}
80
81// SetDirectory
82status_t
83FDManager::SetDirectory(BDirectory* directory, const node_ref* ref)
84{
85	status_t error = directory->SetTo(ref);
86
87	if (error == B_NO_MORE_FDS) {
88		GetDefault()->_IncreaseLimit();
89		error = directory->SetTo(ref);
90	}
91
92	return error;
93}
94
95// SetEntry
96status_t
97FDManager::SetEntry(BEntry* entry, const entry_ref* ref)
98{
99	status_t error = entry->SetTo(ref);
100
101	if (error == B_NO_MORE_FDS) {
102		GetDefault()->_IncreaseLimit();
103		error = entry->SetTo(ref);
104	}
105
106	return error;
107}
108
109// SetEntry
110status_t
111FDManager::SetEntry(BEntry* entry, const char* path)
112{
113	status_t error = entry->SetTo(path);
114
115	if (error == B_NO_MORE_FDS) {
116		GetDefault()->_IncreaseLimit();
117		error = entry->SetTo(path);
118	}
119
120	return error;
121}
122
123// SetFile
124status_t
125FDManager::SetFile(BFile* file, const char* path, uint32 openMode)
126{
127	status_t error = file->SetTo(path, openMode);
128
129	if (error == B_NO_MORE_FDS) {
130		GetDefault()->_IncreaseLimit();
131		error = file->SetTo(path, openMode);
132	}
133
134	return error;
135}
136
137// SetNode
138status_t
139FDManager::SetNode(BNode* node, const entry_ref* ref)
140{
141	status_t error = node->SetTo(ref);
142
143	if (error == B_NO_MORE_FDS) {
144		GetDefault()->_IncreaseLimit();
145		error = node->SetTo(ref);
146	}
147
148	return error;
149}
150
151// Open
152status_t
153FDManager::Open(const char* path, uint32 openMode, mode_t mode, int& fd)
154{
155	status_t error = B_OK;
156	fd = open(path, openMode, mode);
157	if (fd < 0)
158		error = errno;
159
160	if (error == B_NO_MORE_FDS) {
161		GetDefault()->_IncreaseLimit();
162
163		error = B_OK;
164		fd = open(path, openMode, mode);
165		if (fd < 0)
166			error = errno;
167	}
168
169	return error;
170}
171
172// OpenDir
173status_t
174FDManager::OpenDir(const char* path, DIR*& dir)
175{
176	status_t error = B_OK;
177	dir = opendir(path);
178	if (!dir)
179		error = errno;
180
181	if (error == B_NO_MORE_FDS) {
182		GetDefault()->_IncreaseLimit();
183
184		error = B_OK;
185		dir = opendir(path);
186		if (!dir)
187			error = errno;
188	}
189
190	return error;
191}
192
193// OpenAttrDir
194status_t
195FDManager::OpenAttrDir(const char* path, DIR*& dir)
196{
197	status_t error = B_OK;
198	dir = fs_open_attr_dir(path);
199	if (!dir)
200		error = errno;
201
202	if (error == B_NO_MORE_FDS) {
203		GetDefault()->_IncreaseLimit();
204
205		error = B_OK;
206		dir = fs_open_attr_dir(path);
207		if (!dir)
208			error = errno;
209	}
210
211	return error;
212}
213
214// _IncreaseLimit
215status_t
216FDManager::_IncreaseLimit()
217{
218	AutoLocker<Locker> _(fLock);
219
220	int32 newLimit = fFDLimit + kFDLimitIncrement;
221
222	status_t error = _kset_fd_limit_(newLimit);
223	if (error == B_OK)
224		fFDLimit = newLimit;
225
226	return error;
227}
228
229
230// sManager
231FDManager* FDManager::sManager = NULL;
232