ot_int sub_fileheaders( alp_tmpl* alp, id_tmpl* user_id, ot_u8 respond, ot_u8 cmd_in, ot_int data_in ) { ot_int data_out = 0; vlBLOCK file_block = (vlBLOCK)((cmd_in >> 4) & 0x07); /// Only run if respond bit is set! if (respond) { while ((data_in > 0) && sub_qnotfull(respond, 6, alp->outq)) { vaddr header; ot_bool allow_output = True; data_in--; // one for the file id allow_output = (ot_bool)(vl_getheader_vaddr(&header, file_block, \ q_readbyte(alp->inq), VL_ACCESS_R, NULL) == 0); if (allow_output) { q_writeshort_be(alp->outq, vworm_read(header + 4)); // id & mod q_writeshort(alp->outq, vworm_read(header + 0)); // length q_writeshort(alp->outq, vworm_read(header + 2)); // alloc data_out += 6; } } //alp->BOOKMARK_IN = (void*)sub_testchunk(data_in); } return data_out; }
vlFILE* vl_open_file(vaddr header) { vlFILE* fp; fp = sub_new_fp(); if (fp != NULL) { fp->header = header; fp->alloc = vworm_read(header + 2); //alloc fp->idmod = vworm_read(header + 4); fp->start = vworm_read(header + 8); //mirror base addr if (fp->start != NULL_vaddr) { ot_u16 mlen = fp->start; fp->start += 2; fp->write = &vsram_mark; fp->read = &vsram_read; fp->length = vsram_read(mlen); } else { fp->write = &vworm_write; fp->read = &vworm_read; fp->length = vworm_read(header + 0); //length fp->start = vworm_read(header + 6); //vworm base addr } } return fp; }
void sub_delete_file(vaddr del_header) { #if (OT_FEATURE(VLNEW) == ENABLED) vaddr header_base; ot_u16 header_alloc; header_alloc = (ot_u16)vworm_read(del_header+2); header_base = (vaddr)vworm_read(del_header+6); // Wipe the old data and mark header as deleted vworm_wipeblock(header_base, header_alloc); vworm_mark((del_header+2), 0); //alloc vworm_mark((del_header+6), NULL_vaddr); //base #endif }
ot_u8 sub_isf_mirror(ot_u8 direction) { vaddr header; vaddr header_base; vaddr header_alloc; vaddr header_mirror; //vaddr header_end; ot_int i; ot_u16* mirror_ptr; // Go through ISF Header array header = ISF_Header_START; for (i=0; i<ISF_NUM_STOCK_FILES; i++, header+=sizeof(vl_header)) { //get header data header_alloc = vworm_read(header+2); header_base = vworm_read(header+6); header_mirror = vworm_read(header+8); // Copy vworm to mirror if there is a mirror // 0. Skip unmirrored or uninitialized, or unallocated files // 1. Resolve Mirror Length (in vsram it is right ahead of the data) // 2. Load/Save Mirror Data (header_alloc is repurposed) if ((header_mirror != NULL_vaddr) && (header_alloc != 0)) { mirror_ptr = (ot_u16*)vsram_get(header_mirror); if (direction == MIRROR_TO_SRAM) { // LOAD *mirror_ptr = vworm_read(header+0); } if (header_base == NULL_vaddr) { // EXIT if file is mirror-only continue; } if (direction != MIRROR_TO_SRAM) { // SAVE vworm_write((header+0), *mirror_ptr); } header_alloc = header_base + *mirror_ptr; mirror_ptr++; for ( ; header_base<header_alloc; header_base+=2, mirror_ptr++) { if (direction == MIRROR_TO_SRAM) { *mirror_ptr = vworm_read(header_base); } else { vworm_write(header_base, *mirror_ptr); } } } } return 0; }
ot_u8 vl_getheader_vaddr(vaddr* header, vlBLOCK block_id, ot_u8 data_id, ot_u8 mod, id_tmpl* user_id) { /// 1. Get the header from the supplied Block ID & Data ID switch (block_id) { case VL_GFB_BLOCKID: *header = sub_gfb_search(data_id); break; case VL_ISFS_BLOCKID: *header = sub_isfs_search(data_id); break; case VL_ISF_BLOCKID: *header = sub_isf_search(data_id); break; default: return 255; } /// 2. Bail if header is NULL if (*header == NULL_vaddr) { return 0x01; } /// 3. Authenticate, when it's not a su call if (user_id != NULL) { Twobytes filemod; filemod.ushort = vworm_read(*header + 4); if ( auth_check(filemod.ubyte[1], mod, user_id) == 0 ) { return 0x04; } } return 0; }
vaddr sub_header_search(vaddr header, ot_u8 search_id, ot_int num_headers) { Twobytes idmod; ot_u16 base; for (; num_headers > 0; num_headers--) { base = vworm_read(header + 6); idmod.ushort = vworm_read(header + 4); if ( base != 0 && base != 0xFFFF) { if (idmod.ubyte[0] == search_id) return header; } header += sizeof(vl_header); } return NULL_vaddr; }
void sub_copy_header( vaddr header, ot_u16* output_header ) { ot_int i; ot_int copy_length = sizeof(vl_header) / 2; for (i=0; i<copy_length; i++) { output_header[i] = vworm_read(header); header += 2; } }
vaddr sub_find_empty_header(vaddr header, ot_int num_headers) { vaddr header_base; for (; num_headers>0; num_headers--) { header_base = vworm_read( (header+6) ); if ( header_base == NULL_vaddr ) { return header; } header += sizeof(vl_header); } return NULL_vaddr; }
ot_u8 vl_delete(vlBLOCK block_id, ot_u8 data_id, id_tmpl* user_id) { #if (OT_FEATURE(VLNEW) == ENABLED) vaddr header = NULL_vaddr; sub_vaddr search_fn; sub_check check_fn; /// 1. Get the header from the supplied Block ID & Data ID block_id--; switch (block_id) { case 0: check_fn = &sub_gfb_delete_check; search_fn = &sub_gfb_search; break; case 1: check_fn = &sub_isfs_delete_check; search_fn = &sub_isfs_search; break; case 2: check_fn = &sub_isf_delete_check; search_fn = &sub_isf_search; break; default: return 255; } if (check_fn(data_id) != 0) { header = search_fn(data_id); } /// 2. Bail if header is NULL if (header == NULL_vaddr) { return 0x01; } /// 3. Authenticate, when it's not a su call if (user_id != NULL) { Twobytes filemod; filemod.ushort = vworm_read(header + 4); if ( auth_check(filemod.ubyte[1], VL_ACCESS_RW, user_id) == 0 ) { return 0x04; } } sub_delete_file(header); return 0; #else return 255; //error, delete disabled #endif }
ot_int sub_fileperms( alp_tmpl* alp, id_tmpl* user_id, ot_u8 respond, ot_u8 cmd_in, ot_int data_in ) { ot_int data_out = 0; vlBLOCK file_block = (vlBLOCK)((cmd_in >> 4) & 0x07); ot_u8 file_mod = ((cmd_in & 0x02) ? VL_ACCESS_W : VL_ACCESS_R); /// Loop through all the listed file ids and process permissions. while ((data_in > 0) && sub_qnotfull(respond, 2, alp->outq)) { ot_u8 file_id = q_readbyte(alp->inq); ot_bool allow_write = respond; vaddr header; data_in--; // one for the file id if (file_mod == VL_ACCESS_W ) { /// run the chmod and return the error code (0 is no error) data_in--; // two for the new mod file_mod = vl_chmod(file_block, file_id, q_readbyte(alp->inq), user_id); } else if (allow_write) { /// Get the header address and return mod (offset 5). The root user /// (NULL) is used because this is only for reading filemod. /// Note: This is a hack that is extremely optimized for speed allow_write = (ot_bool)(vl_getheader_vaddr(&header, file_block, file_id, \ VL_ACCESS_R, NULL) == 0); if (allow_write) { Twobytes filemod; filemod.ushort = vworm_read(header + 4); //shortcut to idmod, hack-ish but fast file_mod = filemod.ubyte[1]; } } if (allow_write) { /// load the data onto the output, if response enabled q_writebyte(alp->outq, file_id); q_writebyte(alp->outq, file_mod); data_out += 2; } } /// return number of bytes put onto the output (always x2) //alp->BOOKMARK_IN = (void*)sub_testchunk(data_in); return data_out; }
ot_u8 vl_close( vlFILE* fp ) { if (FP_ISVALID(fp)) { if (fp->read == &vsram_read) { ot_u16* mhead; mhead = (ot_u16*)vsram_get(fp->start-2); *mhead = (*mhead != fp->length) ? fp->length : *mhead; } else if ( vworm_read(fp->header+0) != fp->length ) { sub_write_header( (fp->header+0), &(fp->length), 2); } // Kill file attributes fp->start = 0; fp->length = 0; //fp->header = NULL_vaddr; fp->read = NULL; fp->write = NULL; return 0; } return 255; }
ot_int sub_filedata( alp_tmpl* alp, id_tmpl* user_id, ot_u8 respond, ot_u8 cmd_in, ot_int data_in ) { vlFILE* fp; ot_u16 offset; ot_u16 span; ot_int data_out = 0; ot_bool inc_header = (ot_bool)((cmd_in & 0x0F) == 0x0C); vlBLOCK file_block = (vlBLOCK)((cmd_in >> 4) & 0x07); ot_u8 file_mod = ((cmd_in & 0x02) ? VL_ACCESS_W : VL_ACCESS_R); ot_queue* inq = alp->inq; ot_queue* outq = alp->outq; sub_filedata_TOP: while (data_in > 0) { vaddr header; ot_u8 err_code; ot_u8 file_id; ot_u16 limit; //alp->BOOKMARK_IN = inq->getcursor; //alp->BOOKMARK_OUT = NULL; file_id = q_readbyte(inq); offset = q_readshort(inq); span = q_readshort(inq); limit = offset + span; err_code = vl_getheader_vaddr(&header, file_block, file_id, file_mod, user_id); file_mod = ((file_mod & VL_ACCESS_W) != 0); //fp = NULL; // A. File error catcher Stage // (In this case, gotos make it more readable) /// Make sure file header was retrieved properly, or goto error if (err_code != 0) { goto sub_filedata_senderror; } /// Make sure file opens properly, or goto error fp = vl_open_file(header); if (fp == NULL) { err_code = 0xFF; goto sub_filedata_senderror; } /// Make sure offset is within file bounds, or goto error if (offset >= fp->alloc) { err_code = 0x07; goto sub_filedata_senderror; } if (limit > fp->alloc) { limit = fp->alloc; err_code = 0x08; } // B. File Writing or Reading Stage // Write to file // 1. Process error on bad ALP parameters, but still do partial write // 2. offset, span are adjusted to convey leftover data // 3. miscellaneous write error occurs when vl_write fails if (file_mod) { for (; offset<limit; offset+=2, span-=2, data_in-=2) { if (inq->getcursor >= inq->back) { goto sub_filedata_overrun; } err_code |= vl_write(fp, offset, q_readshort_be(inq)); } } // Read from File // 1. No error for bad read parameter, just fix the limit // 2. If inc_header param is set, include the file header in output // 3. Read out file data else { ot_u8 overhead; //limit = (limit > fp->length) ? fp->length : limit; overhead = 6; overhead += (inc_header != 0) << 2; if ((outq->putcursor+overhead) >= outq->back) { goto sub_filedata_overrun; } q_writeshort_be(outq, vworm_read(header + 4)); // id & mod if (inc_header) { q_writeshort(outq, vworm_read(header + 0)); // length q_writeshort(outq, vworm_read(header + 2)); // alloc data_out += 4; } q_writeshort(outq, offset); q_writeshort(outq, span); data_out += 6; for (; offset<limit; offset+=2, span-=2, data_out+=2) { if ((outq->putcursor+2) >= outq->back) { goto sub_filedata_overrun; } q_writeshort_be(outq, vl_read(fp, offset)); } } // C. Error Sending Stage sub_filedata_senderror: if ((respond != 0) && (err_code | file_mod)) { if ((outq->putcursor+2) >= outq->back) { goto sub_filedata_overrun; } q_writebyte(outq, file_id); q_writebyte(outq, err_code); q_markbyte(inq, span); // go past any leftover input data data_out += 2; } data_in -= 5; // 5 bytes input header vl_close(fp); } // Total Completion: // Set bookmark to NULL, because the record was completely processed //alp->BOOKMARK_IN = NULL; return data_out; // Partial or Non Completion: // Reconfigure last ALP operation, because it was not completely processed ///@todo Bookmarking is obsolete, because the way Chunking is done has /// been revised. Chunked records must be contiguous. ALP-Main will not /// call this app, and thus not call this function, until the message-end /// bit is detected, therefore meaning that all data is received and /// contiguous. This overrun block, thus, should only check the flags for /// chunking, bypass them, and loop back to the top of this function. sub_filedata_overrun: vl_close(fp); ///@todo alp_next_chunk(alp); // { // ot_u8* scratch; // inq->getcursor = (ot_u8*)alp->BOOKMARK_IN; // scratch = inq->getcursor + 1; // *scratch++ = ((ot_u8*)&offset)[UPPER]; // *scratch++ = ((ot_u8*)&offset)[LOWER]; // *scratch++ = ((ot_u8*)&span)[UPPER]; // *scratch = ((ot_u8*)&span)[LOWER]; // } return data_out; }
/// @todo This checks out in testing, although it is a complex function that /// probably merits further testing vaddr sub_find_empty_heap( vaddr heap_base, vaddr heap_end, vaddr header, ot_uint new_alloc, ot_int num_headers) { #if (OT_FEATURE(VLNEW) == ENABLED) //Search all header combinations to find: // - pairs of adjacent files in the heap // - gaps between these pairs // - the smallest gap that is big enough. vaddr loop1 = header; vaddr loop1_base; ot_uint loop1_alloc; vaddr loop2; vaddr loop2_base; //ot_uint loop2_alloc; ///@todo figure out why this is disused ot_int i; ot_int j; ot_int gap; ot_int closest_gap = (ot_int)(heap_end - heap_base); ot_int bestfit_alloc = (ot_int)(32767); vaddr bestfit_base = NULL_vaddr; //vaddr loop1_end = heap_base; for (i=0; i<num_headers; i++, loop1+=sizeof(vl_header) ) { loop1_alloc = vworm_read(loop1 + 2); // load alloc (max) from header loop1_base = vworm_read(loop1 + 6); // load base from header if ( loop1_base != NULL_vaddr ) { // skip if header is deleted, or empty heap_base = (vaddr)(loop1_base + loop1_alloc); loop2 = header; for (j=0; j<num_headers; j++, loop2+=sizeof(vl_header) ) { //loop2_alloc = vworm_read(loop2 + 2); loop2_base = vworm_read(loop2 + 6); if ( (loop2_base != NULL_vaddr) && (loop2_base > heap_base) ) { // if header is valid ... gap = (ot_int)(loop2_base - heap_base); // calc gap between the two files if (gap < closest_gap) { // The closest gap ... closest_gap = gap; // will be between two adjacent ... //heap_base = loop1_end; // files in the heap. } } } } //if (closest_gap >= new_alloc) { // If the gap between loop1 and next file ... // if (closest_gap < bestfit_alloc) { // is big enough for the data we need ... // bestfit_alloc = closest_gap; // and is smaller than other big-enough gaps ... // bestfit_base = heap_base; // then it is the gap we will write into. // } //} if ((closest_gap >= new_alloc) && (closest_gap < bestfit_alloc)) { bestfit_alloc = closest_gap; bestfit_base = heap_base; } } return bestfit_base; #else return NULL_vaddr; #endif }