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 21using namespace FSShell; 22 23 24namespace FSShell { 25 26 27struct 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 45typedef std::list<FileRestriction*> FileRestrictionList; 46 47static FileRestrictionList sFileRestrictions; 48 49 50static FileRestriction* 51find_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 64static FileRestriction* 65find_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 75void 76add_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 98void 99restricted_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 109void 110restricted_file_duped(int oldFD, int newFD) 111{ 112} 113 114 115void 116restricted_file_closed(int fd) 117{ 118} 119 120 121int 122restricted_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 148void 149restricted_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 160static int 161to_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 178fssh_off_t 179fssh_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