/* * Read from an opend file. * Read can not enlarge file. So you should not read outside the size of * the file. If the read exceeds the file size, its result will be truncated. * * This function returns the number of bytes read. */ int sfs_read(int fd, void *buf, int length) { int remaining, to_copy, offset; blkid *bids; int i, n; char *p = (char *)buf; char tmp[BLOCK_SIZE]; u32 cur = fdtable[fd].cur; /* TODO: check if we need to truncate */ if ((cur + length) > fdtable[fd].inode.size) { // Need to truncate, remove the last portion length = fdtable[fd].inode.size - length; } /* TODO: similar to the sfs_write() */ // Get the block ids of content bids = malloc(length/BLOCK_SIZE + 1); n = sfs_get_file_content(bids, fd, cur, length); // Read operation remaining = length; offset = cur % BLOCK_SIZE; if (BLOCK_SIZE - offset > remaining) { to_copy = remaining; } else { to_copy = BLOCK_SIZE - offset; } for (i = 0; i < n; i++) { sfs_read_block((char*)&tmp, bids[i]); memcpy(buf, tmp+offset, to_copy); remaining -= to_copy; offset = 0; if (remaining > BLOCK_SIZE) { to_copy = BLOCK_SIZE - offset; } else { to_copy = remaining; } } // Update variables fdtable[fd].cur += length; free(bids); return length; }
/* * Read from an opened file. * Read can not enlarge file. So you should not read outside the size of * the file. If the read exceeds the file size, its result will be truncated. * * This function returns the number of bytes read. */ int sfs_read(int fd, void *buf, int length) { int remaining, to_copy, offset; int frame_start, frame_end, content_blk, num_blocks; int i, n; char *p = (char *)buf; char inode_ptr[BLOCK_SIZE]; char tmp[BLOCK_SIZE]; u32 cur = fdtable[fd].cur; sfs_inode_t inode; sfs_read_block(inode_ptr, fdtable[fd].inode_bid); inode = *(sfs_inode_t*)inode_ptr; remaining = length; num_blocks = (length / BLOCK_SIZE) + 1; blkid bids[num_blocks]; //Find frame holding the cursor frame_start = cur / (SFS_FRAME_COUNT * BLOCK_SIZE); //Find the frame that would be holding the last byte we want to read frame_end = (cur + length) / (SFS_FRAME_COUNT * BLOCK_SIZE); int num_frames = frame_start - frame_end + 1; content_blk = cur / BLOCK_SIZE; offset = cur % BLOCK_SIZE; //Traverse the frames and check if the length exceeds the //number of frames blkid frame_bid = inode.first_frame; sfs_inode_frame_t frame; int count = 0; int nonzero_block = 0; //Truncate file to the smallest BLOCK //The first and last blocks will have fewer bytes stored //Check frames to determine if all content blocks exist while(count < num_blocks){ //Read the next frame sfs_read_block(tmp, frame_bid); frame = *(sfs_inode_frame_t*)tmp; frame_bid = frame.next; //Count the number of nonzero indices in the content array while(content_blk < SFS_FRAME_COUNT && count < num_blocks){ if(frame.content[content_blk] != 0){ nonzero_block++; count++; content_blk++; } } //Reset index to zero content_blk = 0; if(frame_bid == 0 && count < num_frames){ printf("The specified length exceeds the file size.\n"); break; } } //The length exceeds the number of valid blocks, truncate read if(count < num_blocks){ //Add fewer bytes from first block remaining = BLOCK_SIZE - offset; num_blocks--; //Add the remaining blocks remaining = remaining + num_blocks * BLOCK_SIZE; } else{ remaining = length; } /* TODO: similar to the sfs_write() */ int num_content_blocks = sfs_get_file_content(bids, fd, cur, length); int bid_count = 0; char block_ptr[BLOCK_SIZE]; while(remaining > 0){ to_copy = 0; sfs_read_block(block_ptr, bids[bid_count]); //Case 1: Read block with offset if(offset != 0){ //Partially fill block if(remaining < (BLOCK_SIZE - offset)){ to_copy = remaining; } else{ //Fill entire block to_copy = BLOCK_SIZE - offset; } strncpy(buf, block_ptr+offset, to_copy); offset = 0; } else if(remaining > BLOCK_SIZE){ //Case 2: Write to a full block to_copy = BLOCK_SIZE; strncpy(buf, block_ptr, to_copy); } else{ //Case 3: Write a partial block to_copy = remaining; strncpy(buf, block_ptr, to_copy); } remaining = remaining - to_copy; cur = cur + to_copy; fdtable[fd].cur = cur; bid_count++; } return length - remaining; }
/* * Write to a file. This function can potentially enlarge the file if the * cur+length exceeds the size of file. Also you should be aware that the * cur may already be larger than the size (due to sfs_seek). In such * case, you will need to expand the file as well. * * This function returns number of bytes written. */ int sfs_write(int fd, void *buf, int length) { int remaining, offset, to_copy; char *p = (char *)buf; char tmp[BLOCK_SIZE]; char inode_ptr[BLOCK_SIZE]; u32 cur = fdtable[fd].cur; u32 buf_offset = 0; sfs_inode_t inode; remaining = length; offset = cur % BLOCK_SIZE; int numBids = (length / BLOCK_SIZE) + 1; blkid bids[numBids]; sfs_read_block(inode_ptr, fdtable[fd].inode_bid); inode = *(sfs_inode_t*)inode_ptr; blkid frame_bid = inode.first_frame; /* TODO: check if we need to resize */ sfs_inode_frame_t frame; sfs_read_block(tmp, frame_bid); frame = *(sfs_inode_frame_t*)tmp; if( (length + cur) > inode.size){ u32 new_size = length + cur; fdtable[fd].inode = inode; sfs_resize_file(fd, new_size); } /* TODO: get the block ids of all contents (using sfs_get_file_content() */ int num_blocks = sfs_get_file_content(bids, fd, cur, length); /* TODO: main loop, go through every block, copy the necessary parts to the buffer, consult the hint in the document. Do not forget to flush to the disk. */ char block_ptr[BLOCK_SIZE]; int bid_count = 0; //The block numbers should already be known by this part while(remaining > 0){ to_copy = 0; sfs_read_block(block_ptr, bids[bid_count]); //Case 1: Write to block with offset if(offset != 0){ //Partially fill block if(remaining < (BLOCK_SIZE - offset)){ to_copy = remaining; } else{ //Fill entire block to_copy = BLOCK_SIZE - offset; } strncpy(block_ptr+offset, buf, to_copy); offset = 0; } else if(remaining > BLOCK_SIZE){ //Case 2: Write to a full block to_copy = BLOCK_SIZE; strncpy(block_ptr, buf, to_copy); } else{ //Case 3: Write a partial block to_copy = remaining; strncpy(block_ptr, buf, to_copy); } sfs_write_block(&block_ptr, bids[bid_count]); remaining = remaining - to_copy; cur = cur + to_copy; bid_count++; } fdtable[fd].cur = cur; return length - remaining; }
/* * Write to a file. This function can potentially enlarge the file if the * cur+length exceeds the size of file. Also you should be aware that the * cur may already be larger than the size (due to sfs_seek). In such * case, you will need to expand the file as well. * * This function returns number of bytes written. */ int sfs_write(int fd, void *buf, int length) { int remaining, offset, to_copy; blkid *bids; int i, n; char *p = (char *)buf; char tmp[BLOCK_SIZE]; u32 cur = fdtable[fd].cur; int frame_size, new_nframe, old_nframe; /* TODO: check if we need to resize */ frame_size = BLOCK_SIZE * SFS_FRAME_COUNT; old_nframe = (fdtable[fd].inode.size + frame_size-1)/frame_size; new_nframe = ((cur+length) + frame_size-1)/frame_size; if (new_nframe > old_nframe) { // Need to allocate a new frame sfs_resize_file(fd, fdtable[fd].inode.size + length); } /* TODO: get the block ids of all contents (using sfs_get_file_content() */ bids = malloc(length/BLOCK_SIZE + 1); n = sfs_get_file_content(bids, fd, cur, length); /* TODO: main loop, go through every block, copy the necessary parts to the buffer, consult the hint in the document. Do not forget to flush to the disk. */ remaining = length; offset = cur % BLOCK_SIZE; if (BLOCK_SIZE - offset > remaining) { to_copy = remaining; } else { to_copy = BLOCK_SIZE - offset; } for (i = 0; i < n; i++) { memcpy(tmp + offset , buf, to_copy); sfs_write_block((char*)&tmp, bids[i]); remaining -= to_copy; offset = 0; if (remaining > BLOCK_SIZE) { to_copy = BLOCK_SIZE - offset; } else { to_copy = remaining; } } /* TODO: update the cursor and free the temp buffer for sfs_get_file_content() */ fdtable[fd].cur += length; if (fdtable[fd].inode.size < fdtable[fd].cur) { fdtable[fd].inode.size = fdtable[fd].cur; } sfs_write_block((char*)&(fdtable[fd].inode), fdtable[fd].inode_bid); free(bids); return length; }