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