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 {
FileRestrictionFSShell::FileRestriction28 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*
find_file_restriction(fssh_dev_t device,fssh_ino_t node)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*
find_file_restriction(int fd)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
add_file_restriction(const char * fileName,fssh_off_t startOffset,fssh_off_t endOffset)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
restricted_file_opened(int fd)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
restricted_file_duped(int oldFD,int newFD)110 restricted_file_duped(int oldFD, int newFD)
111 {
112 }
113
114
115 void
restricted_file_closed(int fd)116 restricted_file_closed(int fd)
117 {
118 }
119
120
121 int
restricted_file_restrict_io(int fd,fssh_off_t & pos,fssh_off_t size)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
restricted_file_restrict_stat(struct fssh_stat * st)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
to_platform_seek_mode(int fsshWhence)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
fssh_lseek(int fd,fssh_off_t offset,int whence)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