1 /*
2 * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #ifdef BUILDING_FS_SHELL
8 # include "compat.h"
9 # define B_OK 0
10 # define B_FILE_ERROR EBADF
11 #else
12 # include <BeOSBuildCompatibility.h>
13 #endif
14
15 #include "fs_descriptors.h"
16
17 #include <map>
18
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23
24 #include <fs_attr.h>
25
26 #include <syscalls.h>
27
28 #include "fs_impl.h"
29
30 using std::map;
31
32 static const int kVirtualDescriptorStart = 10000;
33
34 typedef map<int, BPrivate::Descriptor*> DescriptorMap;
35 static DescriptorMap *sDescriptors;
36
37 namespace BPrivate {
38
39
40 static int
dup_maybe_system(int fd)41 dup_maybe_system(int fd)
42 {
43 if (get_descriptor(fd) != NULL)
44 return _kern_dup(fd);
45
46 int clonedFD = dup(fd);
47 return clonedFD >= 0 ? clonedFD : errno;
48 }
49
50
51 static status_t
close_maybe_system(int fd)52 close_maybe_system(int fd)
53 {
54 if (get_descriptor(fd) != NULL)
55 return _kern_close(fd);
56
57 return close(fd) == 0 ? B_OK : errno;
58 }
59
60
61 // #pragma mark - Descriptor
62
63
64 // constructor
~Descriptor()65 Descriptor::~Descriptor()
66 {
67 }
68
69 // IsSystemFD
70 bool
IsSystemFD() const71 Descriptor::IsSystemFD() const
72 {
73 return false;
74 }
75
76 // GetPath
77 status_t
GetPath(string & path) const78 Descriptor::GetPath(string& path) const
79 {
80 return get_path(fd, NULL, path);
81 }
82
83 // GetNodeRef
84 status_t
GetNodeRef(NodeRef & ref)85 Descriptor::GetNodeRef(NodeRef &ref)
86 {
87 struct stat st;
88 status_t error = GetStat(false, &st);
89 if (error != B_OK)
90 return error;
91
92 ref = NodeRef(st);
93
94 return B_OK;
95 }
96
97
98 // #pragma mark - FileDescriptor
99
100
101 // constructor
FileDescriptor(int fd)102 FileDescriptor::FileDescriptor(int fd)
103 {
104 this->fd = fd;
105 }
106
107 // destructor
~FileDescriptor()108 FileDescriptor::~FileDescriptor()
109 {
110 Close();
111 }
112
113 // Close
114 status_t
Close()115 FileDescriptor::Close()
116 {
117 if (fd >= 0) {
118 int oldFD = fd;
119 fd = -1;
120 if (close(oldFD) < 0)
121 return errno;
122 }
123
124 return B_OK;
125 }
126
127 // Dup
128 status_t
Dup(Descriptor * & clone)129 FileDescriptor::Dup(Descriptor *&clone)
130 {
131 int dupFD = dup(fd);
132 if (dupFD < 0)
133 return errno;
134
135 clone = new FileDescriptor(dupFD);
136 return B_OK;
137 }
138
139 // GetStat
140 status_t
GetStat(bool traverseLink,struct stat * st)141 FileDescriptor::GetStat(bool traverseLink, struct stat *st)
142 {
143 if (fstat(fd, st) < 0)
144 return errno;
145 return B_OK;
146 }
147
148 // IsSystemFD
149 bool
IsSystemFD() const150 FileDescriptor::IsSystemFD() const
151 {
152 return true;
153 }
154
155
156 // #pragma mark - DirectoryDescriptor
157
158
159 // constructor
DirectoryDescriptor(DIR * dir,const NodeRef & ref)160 DirectoryDescriptor::DirectoryDescriptor(DIR *dir, const NodeRef &ref)
161 {
162 this->dir = dir;
163 this->ref = ref;
164 }
165
166 // destructor
~DirectoryDescriptor()167 DirectoryDescriptor::~DirectoryDescriptor()
168 {
169 Close();
170 }
171
172 // Close
173 status_t
Close()174 DirectoryDescriptor::Close()
175 {
176 if (dir) {
177 DIR *oldDir = dir;
178 dir = NULL;
179 if (closedir(oldDir) < 0)
180 return errno;
181 }
182
183 return B_OK;
184 }
185
186 // Dup
187 status_t
Dup(Descriptor * & clone)188 DirectoryDescriptor::Dup(Descriptor *&clone)
189 {
190 string path;
191 status_t error = get_path(fd, NULL, path);
192 if (error != B_OK)
193 return error;
194
195 DIR *dupDir = opendir(path.c_str());
196 if (!dupDir)
197 return errno;
198
199 clone = new DirectoryDescriptor(dupDir, ref);
200 return B_OK;
201 }
202
203 // GetStat
204 status_t
GetStat(bool traverseLink,struct stat * st)205 DirectoryDescriptor::GetStat(bool traverseLink, struct stat *st)
206 {
207 // get a usable path
208 string realPath;
209 status_t error = get_path(fd, NULL, realPath);
210 if (error != B_OK)
211 return error;
212
213 // stat
214 int result;
215 result = stat(realPath.c_str(), st);
216
217 if (result < 0)
218 return errno;
219
220 return B_OK;
221 }
222
223 // GetNodeRef
224 status_t
GetNodeRef(NodeRef & ref)225 DirectoryDescriptor::GetNodeRef(NodeRef &ref)
226 {
227 ref = this->ref;
228
229 return B_OK;
230 }
231
232
233 // #pragma mark - SymlinkDescriptor
234
235
236 // constructor
SymlinkDescriptor(const char * path)237 SymlinkDescriptor::SymlinkDescriptor(const char *path)
238 {
239 this->path = path;
240 }
241
242 // Close
243 status_t
Close()244 SymlinkDescriptor::Close()
245 {
246 return B_OK;
247 }
248
249 // Dup
250 status_t
Dup(Descriptor * & clone)251 SymlinkDescriptor::Dup(Descriptor *&clone)
252 {
253 clone = new SymlinkDescriptor(path.c_str());
254 return B_OK;
255 }
256
257 // GetStat
258 status_t
GetStat(bool traverseLink,struct stat * st)259 SymlinkDescriptor::GetStat(bool traverseLink, struct stat *st)
260 {
261 // stat
262 int result;
263 if (traverseLink)
264 result = stat(path.c_str(), st);
265 else
266 result = lstat(path.c_str(), st);
267
268 if (result < 0)
269 return errno;
270
271 return B_OK;
272 }
273
274 // GetPath
275 status_t
GetPath(string & path) const276 SymlinkDescriptor::GetPath(string& path) const
277 {
278 path = this->path;
279 return B_OK;
280 }
281
282
283 // #pragma mark - AttributeDescriptor
284
285
AttributeDescriptor(int fileFD,const char * attribute,uint32 type,int openMode)286 AttributeDescriptor::AttributeDescriptor(int fileFD, const char* attribute,
287 uint32 type, int openMode)
288 :
289 fFileFD(dup_maybe_system(fileFD)),
290 fType(type),
291 fOpenMode(openMode),
292 fData(NULL),
293 fDataSize(0)
294
295 {
296 strlcpy(fAttribute, attribute, sizeof(fAttribute));
297 }
298
299
~AttributeDescriptor()300 AttributeDescriptor::~AttributeDescriptor()
301 {
302 Close();
303 }
304
305
306 status_t
Init()307 AttributeDescriptor::Init()
308 {
309 if (fFileFD < 0)
310 return B_IO_ERROR;
311
312 // stat the attribute
313 attr_info info;
314 if (fs_stat_attr(fFileFD, fAttribute, &info) < 0) {
315 if (errno == B_ENTRY_NOT_FOUND) {
316 if ((fOpenMode & O_CREAT) == 0)
317 return errno;
318
319 // create the attribute
320 if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0)
321 return errno;
322 return B_OK;
323 }
324 return errno;
325 }
326
327 if ((fOpenMode & O_TRUNC) == 0) {
328 // truncate the attribute
329 if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0)
330 return errno;
331 return B_OK;
332 }
333
334 // we have to read in the attribute data
335 if (info.size == 0)
336 return B_OK;
337
338 fData = (uint8*)malloc(info.size);
339 if (fData == NULL)
340 return B_NO_MEMORY;
341
342 fDataSize = info.size;
343
344 ssize_t bytesRead = fs_read_attr(fFileFD, fAttribute, fType, 0, fData,
345 fDataSize);
346 if (bytesRead < 0)
347 return errno;
348 if ((size_t)bytesRead != fDataSize)
349 return B_IO_ERROR;
350
351 return B_OK;
352 }
353
354
355 status_t
Write(off_t offset,const void * buffer,size_t bufferSize)356 AttributeDescriptor::Write(off_t offset, const void* buffer, size_t bufferSize)
357 {
358 if (offset < 0)
359 return B_BAD_VALUE;
360
361 if ((fOpenMode & O_ACCMODE) != O_WRONLY
362 && (fOpenMode & O_ACCMODE) != O_RDWR) {
363 return B_NOT_ALLOWED;
364 }
365
366 // we may need to resize the buffer
367 size_t minSize = (size_t)offset + bufferSize;
368 if (minSize > fDataSize) {
369 uint8* data = (uint8*)realloc(fData, minSize);
370 if (data == NULL)
371 return B_NO_MEMORY;
372
373 if ((size_t)offset > fDataSize)
374 memset(data + offset, 0, offset - fDataSize);
375
376 fData = data;
377 fDataSize = minSize;
378 }
379
380 // copy the data and write all of it
381 if (bufferSize == 0)
382 return B_OK;
383
384 memcpy((uint8*)fData + offset, buffer, bufferSize);
385
386 ssize_t bytesWritten = fs_write_attr(fFileFD, fAttribute, fType, 0,
387 fData, fDataSize);
388 if (bytesWritten < 0)
389 return errno;
390 if ((size_t)bytesWritten != fDataSize)
391 return B_IO_ERROR;
392
393 return B_OK;
394 }
395
396
397 status_t
Close()398 AttributeDescriptor::Close()
399 {
400 if (fFileFD < 0)
401 return B_BAD_VALUE;
402
403 close_maybe_system(fFileFD);
404 fFileFD = -1;
405
406 free(fData);
407 fData = NULL;
408 fDataSize = 0;
409
410 return B_OK;
411 }
412
413
414 status_t
Dup(Descriptor * & clone)415 AttributeDescriptor::Dup(Descriptor*& clone)
416 {
417 return B_NOT_SUPPORTED;
418 }
419
420
421 status_t
GetStat(bool traverseLink,struct stat * st)422 AttributeDescriptor::GetStat(bool traverseLink, struct stat* st)
423 {
424 return B_NOT_SUPPORTED;
425 }
426
427
428 // #pragma mark - AttrDirDescriptor
429
430
431 // constructor
AttrDirDescriptor(DIR * dir,const NodeRef & ref)432 AttrDirDescriptor::AttrDirDescriptor(DIR *dir, const NodeRef &ref)
433 : DirectoryDescriptor(dir, ref)
434 {
435 }
436
437 // destructor
~AttrDirDescriptor()438 AttrDirDescriptor::~AttrDirDescriptor()
439 {
440 Close();
441 }
442
443 // Close
444 status_t
Close()445 AttrDirDescriptor::Close()
446 {
447 if (dir) {
448 DIR *oldDir = dir;
449 dir = NULL;
450 if (fs_close_attr_dir(oldDir) < 0)
451 return errno;
452 }
453
454 return B_OK;
455 }
456
457 // Dup
458 status_t
Dup(Descriptor * & clone)459 AttrDirDescriptor::Dup(Descriptor *&clone)
460 {
461 // we don't allow dup()int attr dir descriptors
462 return B_FILE_ERROR;
463 }
464
465 // GetStat
466 status_t
GetStat(bool traverseLink,struct stat * st)467 AttrDirDescriptor::GetStat(bool traverseLink, struct stat *st)
468 {
469 // we don't allow stat()int attr dir descriptors
470 return B_FILE_ERROR;
471 }
472
473 // GetNodeRef
474 status_t
GetNodeRef(NodeRef & ref)475 AttrDirDescriptor::GetNodeRef(NodeRef &ref)
476 {
477 ref = this->ref;
478
479 return B_OK;
480 }
481
482
483 // get_descriptor
484 Descriptor *
get_descriptor(int fd)485 get_descriptor(int fd)
486 {
487 if (!sDescriptors)
488 return NULL;
489 DescriptorMap::iterator it = sDescriptors->find(fd);
490 if (it == sDescriptors->end())
491 return NULL;
492 return it->second;
493 }
494
495 // add_descriptor
496 int
add_descriptor(Descriptor * descriptor)497 add_descriptor(Descriptor *descriptor)
498 {
499 if (!sDescriptors)
500 sDescriptors = new DescriptorMap;
501
502 int fd = -1;
503 if (FileDescriptor *file = dynamic_cast<FileDescriptor*>(descriptor)) {
504 fd = file->fd;
505 } else {
506 // find a free slot
507 for (fd = kVirtualDescriptorStart;
508 sDescriptors->find(fd) != sDescriptors->end();
509 fd++) {
510 }
511 }
512
513 (*sDescriptors)[fd] = descriptor;
514 descriptor->fd = fd;
515
516 return fd;
517 }
518
519 // delete_descriptor
520 status_t
delete_descriptor(int fd)521 delete_descriptor(int fd)
522 {
523 DescriptorMap::iterator it = sDescriptors->find(fd);
524 if (it == sDescriptors->end())
525 return B_FILE_ERROR;
526
527 status_t error = it->second->Close();
528 delete it->second;
529 sDescriptors->erase(it);
530
531 if (sDescriptors->size() == 0) {
532 delete sDescriptors;
533 sDescriptors = NULL;
534 }
535 return error;
536 }
537
538
539 bool
is_unknown_or_system_descriptor(int fd)540 is_unknown_or_system_descriptor(int fd)
541 {
542 Descriptor* descriptor = get_descriptor(fd);
543 return descriptor == NULL || descriptor->IsSystemFD();
544 }
545
546
547 } // namespace BPrivate
548