1 2 /* 3 * This file contains all the function that handle the dir records 4 * (inodes) for the ISO9660 filesystem. 5 */ 6 7 #include "inc.h" 8 9 #include "uthash.h" 10 11 struct inode_cache { 12 ino_t key; 13 struct inode *value; 14 UT_hash_handle hh; 15 } ; 16 17 struct inode_cache *icache = NULL; 18 19 void read_inode_iso9660(struct inode_dir_entry *i, 20 const struct iso9660_dir_record *dir_rec, struct dir_extent *extent, 21 size_t offset, int name_only); 22 23 #ifdef ISO9660_OPTION_MODE3 24 static void read_inode_extents(struct inode_dir_entry *i, 25 const struct iso9660_dir_record *dir_rec, struct dir_extent *extent, 26 size_t *offset); 27 #endif 28 29 #ifdef ISO9660_OPTION_ROCKRIDGE 30 void read_inode_susp(struct inode_dir_entry *i, 31 const struct iso9660_dir_record *dir_rec, struct buf *bp, size_t offset, 32 int name_only); 33 #endif 34 35 static int check_dir_record(const struct iso9660_dir_record *d, size_t offset); 36 37 int fs_putnode(ino_t ino_nr, unsigned int count) 38 { 39 /* 40 * Find the inode specified by the request message and decrease its 41 * counter. 42 */ 43 struct inode *i_node; 44 45 if ((i_node = get_inode(ino_nr)) == NULL) { 46 puts("ISOFS: trying to free unused inode"); 47 return EINVAL; 48 } 49 if (count > i_node->i_count) { 50 puts("ISOFS: put_node count too high"); 51 return EINVAL; 52 } 53 54 i_node->i_count -= count - 1; 55 put_inode(i_node); 56 return OK; 57 } 58 59 60 struct inode* get_inode(ino_t ino_nr) { 61 /* Return an already opened inode from cache. */ 62 struct inode *i_node = inode_cache_get(ino_nr); 63 64 if (i_node == NULL) 65 return NULL; 66 67 if (i_node->i_count == 0) 68 return NULL; 69 70 return i_node; 71 } 72 73 struct inode* open_inode(ino_t ino_nr) { 74 /* Return an inode from cache. */ 75 struct inode *i_node = inode_cache_get(ino_nr); 76 if (i_node == NULL) 77 return NULL; 78 79 i_node->i_count++; 80 81 return i_node; 82 } 83 84 void put_inode(struct inode *i_node) { 85 if (i_node == NULL) 86 return; 87 88 assert(i_node->i_count > 0); 89 i_node->i_count--; 90 91 if(i_node->i_count == 0) 92 i_node->i_mountpoint = FALSE; 93 } 94 95 void dup_inode(struct inode *i_node) { 96 assert(i_node != NULL); 97 assert(i_node->i_count > 0); 98 99 i_node->i_count++; 100 } 101 102 int read_directory(struct inode *dir) { 103 #define MAX_ENTRIES 4096 104 /* Read all entries in a directory. */ 105 size_t pos = 0, cur_entry = 0, cpt; 106 struct inode_dir_entry entries[MAX_ENTRIES]; 107 int status = OK; 108 109 if (dir->dir_contents) 110 return OK; 111 112 if (!S_ISDIR(dir->i_stat.st_mode)) 113 return ENOTDIR; 114 115 for (cur_entry = 0; status == OK && cur_entry < MAX_ENTRIES; cur_entry++) { 116 memset(&entries[cur_entry], 0, sizeof(struct inode_dir_entry)); 117 118 status = read_inode(&entries[cur_entry], &dir->extent, &pos); 119 if (status != OK) 120 break; 121 122 /* Dump the entry if it's not to be exported to userland. */ 123 if (entries[cur_entry].i_node->skip) { 124 free_inode_dir_entry(&entries[cur_entry]); 125 continue; 126 } 127 } 128 129 /* Resize dynamic array to correct size */ 130 dir->dir_contents = alloc_mem(sizeof(struct inode_dir_entry) * cur_entry); 131 memcpy(dir->dir_contents, entries, sizeof(struct inode_dir_entry) * cur_entry); 132 dir->dir_size = cur_entry; 133 134 /* The name pointer has to point to the new memory location. */ 135 for (cpt = 0; cpt < cur_entry; cpt++) { 136 if (dir->dir_contents[cpt].r_name == NULL) 137 dir->dir_contents[cpt].name = 138 dir->dir_contents[cpt].i_name; 139 else 140 dir->dir_contents[cpt].name = 141 dir->dir_contents[cpt].r_name; 142 } 143 144 return (status == EOF) ? OK : status; 145 } 146 147 int check_inodes(void) { 148 /* Check whether there are no more inodes in use. Called on unmount. */ 149 int i; 150 151 /* XXX: actually check for inodes in use. */ 152 return TRUE; 153 } 154 155 int read_inode(struct inode_dir_entry *dir_entry, struct dir_extent *extent, 156 size_t *offset) 157 { 158 struct iso9660_dir_record *dir_rec; 159 struct buf *bp; 160 struct inode *i_node; 161 ino_t ino_nr; 162 int name_only = FALSE; 163 164 /* Find inode. */ 165 bp = read_extent_block(extent, *offset); 166 if (bp == NULL) { 167 return EOF; 168 } 169 170 /* Check if we are crossing a sector boundary. */ 171 dir_rec = (struct iso9660_dir_record*)(b_data(bp) + *offset % 172 v_pri.logical_block_size_l); 173 174 if (dir_rec->length == 0) { 175 *offset = ((*offset / v_pri.logical_block_size_l) + 1) * 176 v_pri.logical_block_size_l; 177 178 lmfs_put_block(bp); 179 bp = read_extent_block(extent, *offset); 180 if (bp == NULL) { 181 return EOF; 182 } 183 184 dir_rec = (struct iso9660_dir_record*)(b_data(bp) + *offset % 185 v_pri.logical_block_size_l); 186 } 187 188 /* Parse basic ISO 9660 specs. */ 189 if (check_dir_record(dir_rec, *offset % v_pri.logical_block_size_l) 190 != OK) { 191 lmfs_put_block(bp); 192 return EINVAL; 193 } 194 195 /* Get inode */ 196 if ((dir_rec->file_flags & D_TYPE) == D_DIRECTORY) { 197 ino_nr = dir_rec->loc_extent_l; 198 } 199 else { 200 ino_nr = get_extent_absolute_block_id(extent, *offset) 201 * v_pri.logical_block_size_l + 202 *offset % v_pri.logical_block_size_l; 203 } 204 205 i_node = inode_cache_get(ino_nr); 206 if (i_node) { 207 /* Inode was already loaded, parse file names only. */ 208 dir_entry->i_node = i_node; 209 i_node->i_refcount++; 210 211 memset(&dir_entry->i_name[0], 0, sizeof(dir_entry->i_name)); 212 213 name_only = TRUE; 214 } 215 else { 216 /* Inode wasn't in memory, parse it. */ 217 i_node = alloc_mem(sizeof(struct inode)); 218 dir_entry->i_node = i_node; 219 i_node->i_refcount = 1; 220 i_node->i_stat.st_ino = ino_nr; 221 inode_cache_add(ino_nr, i_node); 222 } 223 224 dir_entry->i_node = i_node; 225 read_inode_iso9660(dir_entry, dir_rec, extent, *offset, name_only); 226 227 /* Parse extensions. */ 228 #ifdef ISO9660_OPTION_ROCKRIDGE 229 read_inode_susp(dir_entry, dir_rec, bp, 230 *offset % v_pri.logical_block_size_l, name_only); 231 #endif 232 233 *offset += dir_rec->length; 234 if (dir_rec->length % 2) 235 (*offset)++; 236 237 #ifdef ISO9660_OPTION_MODE3 238 read_inode_extents(dir_entry, dir_rec, extent, offset); 239 #endif 240 241 lmfs_put_block(bp); 242 243 return OK; 244 } 245 246 struct inode* inode_cache_get(ino_t ino_nr) { 247 struct inode_cache *i_node; 248 HASH_FIND(hh, icache, &ino_nr, sizeof(ino_t), i_node); 249 250 if (i_node) 251 return i_node->value; 252 else 253 return NULL; 254 } 255 256 void inode_cache_add(ino_t ino_nr, struct inode *i_node) { 257 struct inode_cache *c_check; 258 struct inode_cache *c_entry; 259 260 HASH_FIND(hh, icache, &ino_nr, sizeof(ino_t), c_check); 261 262 if (c_check == NULL) { 263 c_entry = alloc_mem(sizeof(struct inode_cache)); 264 c_entry->key = ino_nr; 265 c_entry->value = i_node; 266 267 HASH_ADD(hh, icache, key, sizeof(ino_t), c_entry); 268 } 269 else 270 panic("Trying to insert inode into cache twice"); 271 } 272 273 void read_inode_iso9660(struct inode_dir_entry *i, 274 const struct iso9660_dir_record *dir_rec, struct dir_extent *extent, 275 size_t offset, int name_only) 276 { 277 char *cp; 278 279 /* Parse file name. */ 280 if (dir_rec->file_id[0] == 0) 281 strcpy(i->i_name, "."); 282 else if (dir_rec->file_id[0] == 1) 283 strcpy(i->i_name, ".."); 284 else { 285 memcpy(i->i_name, dir_rec->file_id, dir_rec->length_file_id); 286 287 /* Truncate/ignore file version suffix. */ 288 cp = strchr(i->i_name, ';'); 289 if (cp != NULL) { 290 *cp = '\0'; 291 /* Truncate dot if file has no extension. */ 292 if (strchr(i->i_name, '.') + 1 == cp) 293 *(cp-1) = '\0'; 294 } 295 } 296 297 if (name_only == TRUE) 298 return; 299 300 /* Parse first extent. */ 301 if (dir_rec->data_length_l > 0) { 302 i->i_node->extent.location = dir_rec->loc_extent_l + 303 dir_rec->ext_attr_rec_length; 304 i->i_node->extent.length = dir_rec->data_length_l / 305 v_pri.logical_block_size_l; 306 307 if (dir_rec->data_length_l % v_pri.logical_block_size_l) 308 i->i_node->extent.length++; 309 310 i->i_node->i_stat.st_size = dir_rec->data_length_l; 311 } 312 313 /* Parse timestamps (record date). */ 314 i->i_node->i_stat.st_atime = i->i_node->i_stat.st_mtime = 315 i->i_node->i_stat.st_ctime = i->i_node->i_stat.st_birthtime = 316 date7_to_time_t(dir_rec->rec_date); 317 318 if ((dir_rec->file_flags & D_TYPE) == D_DIRECTORY) 319 i->i_node->i_stat.st_mode = S_IFDIR; 320 else 321 i->i_node->i_stat.st_mode = S_IFREG; 322 323 i->i_node->i_stat.st_mode |= 0555; 324 325 /* Initialize stat. */ 326 i->i_node->i_stat.st_dev = fs_dev; 327 i->i_node->i_stat.st_blksize = v_pri.logical_block_size_l; 328 i->i_node->i_stat.st_blocks = 329 dir_rec->data_length_l / v_pri.logical_block_size_l; 330 i->i_node->i_stat.st_nlink = 1; 331 } 332 333 #ifdef ISO9660_OPTION_ROCKRIDGE 334 335 void read_inode_susp(struct inode_dir_entry *i, 336 const struct iso9660_dir_record *dir_rec, struct buf *bp, size_t offset, 337 int name_only) 338 { 339 int susp_offset, susp_size, name_length; 340 struct rrii_dir_record rrii_data; 341 342 susp_offset = 33 + dir_rec->length_file_id; 343 /* Get rid of padding byte. */ 344 if(dir_rec->length_file_id % 2 == 0) { 345 susp_offset++; 346 } 347 348 if(dir_rec->length - susp_offset < 4) 349 return; 350 351 susp_size = dir_rec->length - susp_offset; 352 353 /* Initialize record with known, sane data. */ 354 memcpy(rrii_data.mtime, dir_rec->rec_date, ISO9660_SIZE_DATE7); 355 memcpy(rrii_data.atime, dir_rec->rec_date, ISO9660_SIZE_DATE7); 356 memcpy(rrii_data.ctime, dir_rec->rec_date, ISO9660_SIZE_DATE7); 357 memcpy(rrii_data.birthtime, dir_rec->rec_date, ISO9660_SIZE_DATE7); 358 359 rrii_data.d_mode = i->i_node->i_stat.st_mode; 360 rrii_data.uid = SYS_UID; 361 rrii_data.gid = SYS_GID; 362 rrii_data.rdev = NO_DEV; 363 rrii_data.file_id_rrip[0] = '\0'; 364 rrii_data.slink_rrip[0] = '\0'; 365 rrii_data.reparented_inode = NULL; 366 367 parse_susp_buffer(&rrii_data, b_data(bp)+offset+susp_offset, susp_size); 368 369 /* Copy back data from rrii_dir_record structure. */ 370 if (rrii_data.file_id_rrip[0] != '\0') { 371 name_length = strlen(rrii_data.file_id_rrip); 372 i->r_name = alloc_mem(name_length + 1); 373 memcpy(i->r_name, rrii_data.file_id_rrip, name_length); 374 } 375 376 if (rrii_data.slink_rrip[0] != '\0') { 377 name_length = strlen(rrii_data.slink_rrip); 378 i->i_node->s_name = alloc_mem(name_length + 1); 379 memcpy(i->i_node->s_name, rrii_data.slink_rrip, name_length); 380 } 381 382 if (rrii_data.reparented_inode) { 383 /* Recycle the inode already parsed. */ 384 i->i_node = rrii_data.reparented_inode; 385 return; 386 } 387 388 /* XXX: not the correct way to ignore reparented directory holder... */ 389 if (strcmp(rrii_data.file_id_rrip, ".rr_moved") == 0) 390 i->i_node->skip = 1; 391 392 if (name_only == TRUE) 393 return; 394 395 /* Write back all Rock Ridge properties. */ 396 i->i_node->i_stat.st_atime = date7_to_time_t(rrii_data.atime); 397 i->i_node->i_stat.st_ctime = date7_to_time_t(rrii_data.ctime); 398 i->i_node->i_stat.st_mtime = date7_to_time_t(rrii_data.mtime); 399 i->i_node->i_stat.st_birthtime = date7_to_time_t(rrii_data.birthtime); 400 401 i->i_node->i_stat.st_mode = rrii_data.d_mode; 402 i->i_node->i_stat.st_uid = rrii_data.uid; 403 i->i_node->i_stat.st_gid = rrii_data.gid; 404 i->i_node->i_stat.st_rdev = rrii_data.rdev; 405 } 406 407 #endif 408 409 #ifdef ISO9660_OPTION_MODE3 410 411 void read_inode_extents(struct inode *i, 412 const struct iso9660_dir_record *dir_rec, 413 struct dir_extent *extent, size_t *offset) 414 { 415 panic("read_inode_extents() isn't implemented yet!"); 416 } 417 418 #endif 419 420 int check_dir_record(const struct iso9660_dir_record *d, size_t offset) { 421 /* Run some consistency check on a directory entry. */ 422 if ((d->length < 33) || (d->length_file_id < 1)) 423 return EINVAL; 424 if (d->length_file_id + 32 > d->length) 425 return EINVAL; 426 if (offset + d->length > v_pri.logical_block_size_l) 427 return EINVAL; 428 429 return OK; 430 } 431