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