xref: /haiku/src/tools/fs_shell/partition_support.cpp (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
1 /*
2  * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "compatibility.h"
7 
8 #include "partition_support.h"
9 
10 #include <errno.h>
11 #include <unistd.h>
12 
13 #include <list>
14 
15 #include "fssh_errno.h"
16 #include "fssh_stat.h"
17 #include "fssh_unistd.h"
18 #include "stat_priv.h"
19 
20 
21 using namespace FSShell;
22 
23 
24 namespace FSShell {
25 
26 
27 struct FileRestriction {
28 	FileRestriction(fssh_dev_t device, fssh_ino_t node, fssh_off_t startOffset,
29 			fssh_off_t endOffset)
30 		:
31 		device(device),
32 		node(node),
33 		startOffset(startOffset),
34 		endOffset(endOffset)
35 	{
36 	}
37 
38 	fssh_dev_t	device;
39 	fssh_ino_t	node;
40 	fssh_off_t	startOffset;
41 	fssh_off_t	endOffset;
42 };
43 
44 
45 typedef std::list<FileRestriction*> FileRestrictionList;
46 
47 static FileRestrictionList sFileRestrictions;
48 
49 
50 static FileRestriction*
51 find_file_restriction(fssh_dev_t device, fssh_ino_t node)
52 {
53 	for (FileRestrictionList::iterator it = sFileRestrictions.begin();
54 			it != sFileRestrictions.end(); ++it) {
55 		FileRestriction* restriction = *it;
56 		if (restriction->device == device && restriction->node == node)
57 			return restriction;
58 	}
59 
60 	return NULL;
61 }
62 
63 
64 static FileRestriction*
65 find_file_restriction(int fd)
66 {
67 	struct fssh_stat st;
68 	if (unrestricted_fstat(fd, &st) < 0)
69 		return NULL;
70 
71 	return find_file_restriction(st.fssh_st_dev, st.fssh_st_ino);
72 }
73 
74 
75 void
76 add_file_restriction(const char* fileName, fssh_off_t startOffset,
77 	fssh_off_t endOffset)
78 {
79 	struct fssh_stat st;
80 	if (unrestricted_stat(fileName, &st) < 0)
81 		return;
82 
83 	fssh_dev_t device = st.fssh_st_dev;
84 	fssh_ino_t node = st.fssh_st_ino;
85 
86 	FileRestriction* restriction = find_file_restriction(device, node);
87 	if (restriction)
88 		return;
89 
90 	if (endOffset < 0)
91 		endOffset = st.fssh_st_size;
92 
93 	restriction = new FileRestriction(device, node, startOffset, endOffset);
94 	sFileRestrictions.push_back(restriction);
95 }
96 
97 
98 void
99 restricted_file_opened(int fd)
100 {
101 	FileRestriction* restriction = find_file_restriction(fd);
102 	if (!restriction)
103 		return;
104 
105 	lseek(fd, restriction->startOffset, SEEK_SET);
106 }
107 
108 
109 void
110 restricted_file_duped(int oldFD, int newFD)
111 {
112 }
113 
114 
115 void
116 restricted_file_closed(int fd)
117 {
118 }
119 
120 
121 int
122 restricted_file_restrict_io(int fd, fssh_off_t& pos, fssh_off_t size)
123 {
124 	FileRestriction* restriction = find_file_restriction(fd);
125 	if (!restriction)
126 		return 0;
127 
128 	if (pos < 0) {
129 		pos = lseek(fd, 0, SEEK_CUR);
130 		if (pos < 0)
131 			return -1;
132 	} else
133 		pos += restriction->startOffset;
134 
135 	if (pos < restriction->startOffset || pos > restriction->endOffset) {
136 		fssh_set_errno(B_BAD_VALUE);
137 		return -1;
138 	}
139 
140 	fssh_off_t maxSize = restriction->endOffset - pos;
141 	if (size > maxSize)
142 		size = maxSize;
143 
144 	return 0;
145 }
146 
147 
148 void
149 restricted_file_restrict_stat(struct fssh_stat* st)
150 {
151 	FileRestriction* restriction = find_file_restriction(st->fssh_st_dev,
152 		st->fssh_st_ino);
153 	if (!restriction)
154 		return;
155 
156 	st->fssh_st_size = restriction->endOffset - restriction->startOffset;
157 }
158 
159 
160 static int
161 to_platform_seek_mode(int fsshWhence)
162 {
163 	switch (fsshWhence) {
164 		case FSSH_SEEK_CUR:
165 			return SEEK_CUR;
166 		case FSSH_SEEK_END:
167 			return SEEK_END;
168 		case FSSH_SEEK_SET:
169 		default:
170 			return SEEK_SET;
171 	}
172 }
173 
174 
175 }	// namespace FSShell
176 
177 
178 fssh_off_t
179 fssh_lseek(int fd, fssh_off_t offset, int whence)
180 {
181 	FileRestriction* restriction = find_file_restriction(fd);
182 	if (!restriction)
183 		return lseek(fd, offset, to_platform_seek_mode(whence));
184 
185 	fssh_off_t pos;
186 
187 	switch (whence) {
188 		case FSSH_SEEK_CUR:
189 		{
190 			pos = lseek(fd, 0, SEEK_CUR);
191 			if (pos < 0)
192 				return pos;
193 			pos += offset;
194 			break;
195 		}
196 		case FSSH_SEEK_END:
197 			pos = restriction->endOffset + offset;
198 			break;
199 		case FSSH_SEEK_SET:
200 		default:
201 			pos = restriction->startOffset + offset;
202 			break;
203 	}
204 
205 	if (pos < restriction->startOffset) {
206 		fssh_set_errno(B_BAD_VALUE);
207 		return -1;
208 	}
209 
210 	pos = lseek(fd, pos, SEEK_SET);
211 	if (pos >= 0)
212 		pos -= restriction->startOffset;
213 
214 	return pos;
215 }
216