xref: /haiku/src/add-ons/kernel/file_systems/shared/DeviceOpener.cpp (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
1 /*
2  * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "file_systems/DeviceOpener.h"
8 
9 #ifndef FS_SHELL
10 #	include <errno.h>
11 #	include <Drivers.h>
12 #	include <fs_cache.h>
13 #endif
14 
15 
16 DeviceOpener::DeviceOpener(const char* device, int mode)
17 	:
18 	fBlockCache(NULL)
19 {
20 	Open(device, mode);
21 }
22 
23 
24 DeviceOpener::DeviceOpener(int fd, int mode)
25 	:
26 	fBlockCache(NULL)
27 {
28 	Open(fd, mode);
29 }
30 
31 
32 DeviceOpener::~DeviceOpener()
33 {
34 	if (fDevice >= 0){
35 		RemoveCache(false);
36 		close(fDevice);
37 	}
38 }
39 
40 
41 int
42 DeviceOpener::Open(const char* device, int mode)
43 {
44 	fDevice = open(device, mode | O_NOCACHE);
45 	if (fDevice < 0)
46 		fDevice = errno;
47 
48 	if (fDevice < 0 && _IsReadWrite(mode)) {
49 		return Open(device, O_RDONLY | O_NOCACHE);
50 	}
51 
52 	if (fDevice >= 0) {
53 		fMode = mode;
54 		if (_IsReadWrite(mode)) {
55 			device_geometry geometry;
56 			if (!ioctl(fDevice, B_GET_GEOMETRY, &geometry,
57 						sizeof(device_geometry)))
58 			{
59 				if (geometry.read_only) {
60 					close(fDevice);
61 					return Open(device, O_RDONLY | O_NOCACHE);
62 				}
63 			}
64 		}
65 	}
66 	return fDevice;
67 }
68 
69 
70 int
71 DeviceOpener::Open(int fd, int mode)
72 {
73 	fDevice = dup(fd);
74 	if (fDevice < 0)
75 		return errno;
76 
77 	fMode = mode;
78 
79 	return fDevice;
80 }
81 
82 
83 void*
84 DeviceOpener::InitCache(off_t numBlocks, uint32 blockSize)
85 {
86 	return fBlockCache = block_cache_create(fDevice, numBlocks, blockSize,
87 		IsReadOnly());
88 }
89 
90 
91 void
92 DeviceOpener::RemoveCache(bool allowWrites)
93 {
94 	if (fBlockCache == NULL)
95 		return;
96 
97 	block_cache_delete(fBlockCache, allowWrites);
98 	fBlockCache = NULL;
99 }
100 
101 
102 void
103 DeviceOpener::Keep()
104 {
105 	fDevice = -1;
106 }
107 
108 
109 status_t
110 DeviceOpener::GetSize(off_t* _size, uint32* _blockSize)
111 {
112 	device_geometry geometry;
113 	if (ioctl(fDevice, B_GET_GEOMETRY, &geometry,
114 				sizeof(device_geometry)) < 0) {
115 		// maybe it's just a file
116 		struct stat stat;
117 		if (fstat(fDevice, &stat) < 0)
118 			return B_ERROR;
119 
120 		if (_size)
121 			*_size = stat.st_size;
122 		if (_blockSize)	// that shouldn't cause us any problems
123 			*_blockSize = 512;
124 
125 		return B_OK;
126 	}
127 
128 	if (_size) {
129 		*_size = 1ULL * geometry.head_count * geometry.cylinder_count
130 			* geometry.sectors_per_track * geometry.bytes_per_sector;
131 	}
132 	if (_blockSize)
133 		*_blockSize = geometry.bytes_per_sector;
134 
135 	return B_OK;
136 }
137