vfs: check userland buffers before reading them.
[haiku.git] / src / tools / fs_shell / partition_support.cpp
blob7843f5162d7bb6af209a9a60876ffcca6285474b
1 /*
2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
6 #include "compatibility.h"
8 #include "partition_support.h"
10 #include <errno.h>
11 #include <unistd.h>
13 #include <list>
15 #include "fssh_errno.h"
16 #include "fssh_stat.h"
17 #include "fssh_unistd.h"
18 #include "stat_priv.h"
21 using namespace FSShell;
24 namespace FSShell {
27 struct FileRestriction {
28 FileRestriction(fssh_dev_t device, fssh_ino_t node, fssh_off_t startOffset,
29 fssh_off_t endOffset)
31 device(device),
32 node(node),
33 startOffset(startOffset),
34 endOffset(endOffset)
38 fssh_dev_t device;
39 fssh_ino_t node;
40 fssh_off_t startOffset;
41 fssh_off_t endOffset;
45 typedef std::list<FileRestriction*> FileRestrictionList;
47 static FileRestrictionList sFileRestrictions;
50 static FileRestriction*
51 find_file_restriction(fssh_dev_t device, fssh_ino_t node)
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;
60 return NULL;
64 static FileRestriction*
65 find_file_restriction(int fd)
67 struct fssh_stat st;
68 if (unrestricted_fstat(fd, &st) < 0)
69 return NULL;
71 return find_file_restriction(st.fssh_st_dev, st.fssh_st_ino);
75 void
76 add_file_restriction(const char* fileName, fssh_off_t startOffset,
77 fssh_off_t endOffset)
79 struct fssh_stat st;
80 if (unrestricted_stat(fileName, &st) < 0)
81 return;
83 fssh_dev_t device = st.fssh_st_dev;
84 fssh_ino_t node = st.fssh_st_ino;
86 FileRestriction* restriction = find_file_restriction(device, node);
87 if (restriction)
88 return;
90 if (endOffset < 0)
91 endOffset = st.fssh_st_size;
93 restriction = new FileRestriction(device, node, startOffset, endOffset);
94 sFileRestrictions.push_back(restriction);
98 void
99 restricted_file_opened(int fd)
101 FileRestriction* restriction = find_file_restriction(fd);
102 if (!restriction)
103 return;
105 lseek(fd, restriction->startOffset, SEEK_SET);
109 void
110 restricted_file_duped(int oldFD, int newFD)
115 void
116 restricted_file_closed(int fd)
122 restricted_file_restrict_io(int fd, fssh_off_t& pos, fssh_off_t size)
124 FileRestriction* restriction = find_file_restriction(fd);
125 if (!restriction)
126 return 0;
128 if (pos < 0) {
129 pos = lseek(fd, 0, SEEK_CUR);
130 if (pos < 0)
131 return -1;
132 } else
133 pos += restriction->startOffset;
135 if (pos < restriction->startOffset || pos > restriction->endOffset) {
136 fssh_set_errno(B_BAD_VALUE);
137 return -1;
140 fssh_off_t maxSize = restriction->endOffset - pos;
141 if (size > maxSize)
142 size = maxSize;
144 return 0;
148 void
149 restricted_file_restrict_stat(struct fssh_stat* st)
151 FileRestriction* restriction = find_file_restriction(st->fssh_st_dev,
152 st->fssh_st_ino);
153 if (!restriction)
154 return;
156 st->fssh_st_size = restriction->endOffset - restriction->startOffset;
160 static int
161 to_platform_seek_mode(int fsshWhence)
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;
175 } // namespace FSShell
178 fssh_off_t
179 fssh_lseek(int fd, fssh_off_t offset, int whence)
181 FileRestriction* restriction = find_file_restriction(fd);
182 if (!restriction)
183 return lseek(fd, offset, to_platform_seek_mode(whence));
185 fssh_off_t pos;
187 switch (whence) {
188 case FSSH_SEEK_CUR:
190 pos = lseek(fd, 0, SEEK_CUR);
191 if (pos < 0)
192 return pos;
193 pos += offset;
194 break;
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;
205 if (pos < restriction->startOffset) {
206 fssh_set_errno(B_BAD_VALUE);
207 return -1;
210 pos = lseek(fd, pos, SEEK_SET);
211 if (pos >= 0)
212 pos -= restriction->startOffset;
214 return pos;