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