xref: /haiku/src/tools/fs_shell/partition_support.cpp (revision ed6250c95736c0b55da79d6e9dd01369532260c0)
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 namespace FSShell {
22 
23 
24 struct FileRestriction {
25 	FileRestriction(fssh_dev_t device, fssh_ino_t node, fssh_off_t startOffset,
26 		fssh_off_t endOffset)
27 		: device(device),
28 		  node(node),
29 		  startOffset(startOffset),
30 		  endOffset(endOffset)
31 	{
32 	}
33 
34 	fssh_dev_t	device;
35 	fssh_ino_t	node;
36 	fssh_off_t	startOffset;
37 	fssh_off_t	endOffset;
38 };
39 
40 
41 typedef std::list<FileRestriction*> FileRestrictionList;
42 
43 static FileRestrictionList sFileRestrictions;
44 
45 
46 static FileRestriction*
47 find_file_restriction(fssh_dev_t device, fssh_ino_t node)
48 {
49 	for (FileRestrictionList::iterator it = sFileRestrictions.begin();
50 		it != sFileRestrictions.end();
51 		++it) {
52 		FileRestriction* restriction = *it;
53 		if (restriction->device == device && restriction->node == node)
54 			return restriction;
55 	}
56 
57 	return NULL;
58 }
59 
60 
61 static FileRestriction*
62 find_file_restriction(int fd)
63 {
64 	struct fssh_stat st;
65 	if (unrestricted_fstat(fd, &st) < 0)
66 		return NULL;
67 
68 	return find_file_restriction(st.fssh_st_dev, st.fssh_st_ino);
69 }
70 
71 
72 void
73 add_file_restriction(const char* fileName, fssh_off_t startOffset,
74 	fssh_off_t endOffset)
75 {
76 	struct fssh_stat st;
77 	if (unrestricted_stat(fileName, &st) < 0)
78 		return;
79 
80 	fssh_dev_t device = st.fssh_st_dev;
81 	fssh_ino_t node = st.fssh_st_ino;
82 
83 	FileRestriction* restriction = find_file_restriction(device, node);
84 	if (restriction)
85 		return;
86 
87 	if (endOffset < 0)
88 		endOffset = st.fssh_st_size;
89 
90 	restriction = new FileRestriction(device, node, startOffset, endOffset);
91 	sFileRestrictions.push_back(restriction);
92 }
93 
94 
95 void
96 restricted_file_opened(int fd)
97 {
98 	FileRestriction* restriction = find_file_restriction(fd);
99 	if (!restriction)
100 		return;
101 
102 	lseek(fd, restriction->startOffset, SEEK_SET);
103 }
104 
105 
106 void
107 restricted_file_duped(int oldFD, int newFD)
108 {
109 }
110 
111 
112 void
113 restricted_file_closed(int fd)
114 {
115 }
116 
117 
118 int
119 restricted_file_restrict_io(int fd, fssh_off_t& pos, fssh_off_t size)
120 {
121 	FileRestriction* restriction = find_file_restriction(fd);
122 	if (!restriction)
123 		return 0;
124 
125 	if (pos < 0) {
126 		pos = lseek(fd, 0, SEEK_CUR);
127 		if (pos < 0)
128 			return -1;
129 	} else
130 		pos += restriction->startOffset;
131 
132 	if (pos < restriction->startOffset || pos > restriction->endOffset) {
133 		fssh_set_errno(B_BAD_VALUE);
134 		return -1;
135 	}
136 
137 	fssh_off_t maxSize = restriction->endOffset - pos;
138 	if (size > maxSize)
139 		size = maxSize;
140 
141 	return 0;
142 }
143 
144 
145 #include <stdio.h>
146 void
147 restricted_file_restrict_stat(struct fssh_stat* st)
148 {
149 	FileRestriction* restriction = find_file_restriction(st->fssh_st_dev,
150 		st->fssh_st_ino);
151 	if (!restriction)
152 		return;
153 
154 printf("restricted_file_restrict_stat(): startOffset: %lld, endOffset: %lld\n",
155 restriction->startOffset, restriction->endOffset);
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 fssh_off_t
176 fssh_lseek(int fd, fssh_off_t offset, int whence)
177 {
178 	FileRestriction* restriction = find_file_restriction(fd);
179 	if (!restriction)
180 		return lseek(fd, offset, to_platform_seek_mode(whence));
181 
182 	fssh_off_t pos;
183 
184 	switch (whence) {
185 		case FSSH_SEEK_CUR:
186 		{
187 			pos = lseek(fd, 0, SEEK_CUR);
188 			if (pos < 0)
189 				return pos;
190 			pos += offset;
191 			break;
192 		}
193 		case FSSH_SEEK_END:
194 			pos = restriction->endOffset + offset;
195 			break;
196 		case FSSH_SEEK_SET:
197 		default:
198 			pos = restriction->startOffset + offset;
199 			break;
200 	}
201 
202 	if (pos < restriction->startOffset) {
203 		fssh_set_errno(B_BAD_VALUE);
204 		return -1;
205 	}
206 
207 	pos = lseek(fd, pos, SEEK_SET);
208 	if (pos >= 0)
209 		pos -= restriction->startOffset;
210 
211 	return pos;
212 }
213 
214 
215 }	// namespace FSShell
216