/*===========================================================================* * fs_readwrite * *===========================================================================*/ PUBLIC int fs_readwrite(void) { int r, rw_flag, block_spec; int regular; cp_grant_id_t gid; off_t position, f_size, bytes_left; unsigned int off, cum_io, block_size, chunk; mode_t mode_word; int completed; struct inode *rip; size_t nrbytes; r = OK; /* Find the inode referred */ if ((rip = find_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); mode_word = rip->i_mode & I_TYPE; /* immediate files are regular files too! */ regular = (mode_word == I_REGULAR || mode_word == I_IMMEDIATE || mode_word == I_NAMED_PIPE); block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0); /* Determine blocksize */ if (block_spec) { block_size = get_block_size( (dev_t) rip->i_zone[0]); f_size = MAX_FILE_POS; } else { block_size = rip->i_sp->s_block_size; f_size = rip->i_size; } /* Get the values from the request message */ rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; position = (off_t) fs_m_in.REQ_SEEK_POS_LO; nrbytes = (size_t) fs_m_in.REQ_NBYTES; rdwt_err = OK; /* set to EIO if disk error occurs */ if (rw_flag == WRITING && !block_spec && (rip->i_mode & I_TYPE) != I_IMMEDIATE) { /* Check in advance to see if file will grow too big. */ if (position > (off_t) (rip->i_sp->s_max_size - nrbytes)) return(EFBIG); /* Clear the zone containing present EOF if hole about * to be created. This is necessary because all unwritten * blocks prior to the EOF must read as zeros. */ if(position > f_size) clear_zone(rip, f_size, 0); } cum_io = 0; if((rip->i_mode & I_TYPE) == I_IMMEDIATE) { int sanity = 0; if(f_size > 40) printf("Immediate file is %d bytes!\n", f_size); if(rw_flag == WRITING) { /* printf("fs_readwrite() WRITING to immediate file\n"); */ /* is the file going to need to be upconverted from immediate to regular? */ if((f_size + nrbytes) > 40 || position > 40) { char tmp[40]; register int i; register struct buf *bp; for(i = 0; i < f_size; i++) { tmp[i] = *(((char *)rip->i_zone) + i); } /* clear inode since it will now hold pointers rather than data (copied from wipe_inode()) */ rip->i_size = 0; rip->i_update = ATIME | CTIME | MTIME; /* update all times later */ rip->i_dirt = DIRTY; for (i = 0; i < V2_NR_TZONES; i++) rip->i_zone[i] = NO_ZONE; /* Writing to a nonexistent block. Create and enter in inode.*/ if ((bp = new_block(rip, (off_t) 0)) == NULL) panic("bp not valid in fs_readwrite immediate growth; this can't be happening!"); /* copy data to bp->data */ for(i = 0; i < f_size; i++) { bp->b_data[i] = tmp[i]; } bp->b_dirt = DIRTY; put_block(bp, PARTIAL_DATA_BLOCK); position += f_size; f_size = rip->i_size; rip->i_mode = (I_REGULAR | (rip->i_mode & ALL_MODES)); } /* the file will not grow over 40 bytes */ else { sanity = 1; } } else { /* printf("fs_readwrite() READING from immediate file\n"); */ bytes_left = f_size - position; /* if the position is past the end of the file, it is already too late... */ if(bytes_left > 0) { sanity = 1; /* don't read past the EOF, just right up to it */ if(nrbytes > bytes_left) nrbytes = bytes_left; } } if(sanity) { r = rw_immed(rip, position, nrbytes, rw_flag, gid, cum_io); if(r == OK) { cum_io += nrbytes; position += nrbytes; /* no more bytes left to read */ nrbytes = 0; } } } /* Split the transfer into chunks that don't span two blocks. */ while (nrbytes > 0) { off = ((unsigned int) position) % block_size; /* offset in blk*/ chunk = min(nrbytes, block_size - off); if (rw_flag == READING) { bytes_left = f_size - position; if (position >= f_size) break; /* we are beyond EOF */ if (chunk > (unsigned int) bytes_left) chunk = bytes_left; } /* Read or write 'chunk' bytes. */ r = rw_chunk(rip, cvul64((unsigned long) position), off, chunk, nrbytes, rw_flag, gid, cum_io, block_size, &completed); if (r != OK) break; /* EOF reached */ if (rdwt_err < 0) break; /* Update counters and pointers. */ nrbytes -= chunk; /* bytes yet to be read */ cum_io += chunk; /* bytes read so far */ position += (off_t) chunk; /* position within the file */ } fs_m_out.RES_SEEK_POS_LO = position; /* It might change later and the VFS has to know this value */ /* On write, update file size and access time. */ if (rw_flag == WRITING) { if (regular || mode_word == I_DIRECTORY) { if (position > f_size) rip->i_size = position; } } /* Check to see if read-ahead is called for, and if so, set it up. */ if(rw_flag == READING && rip->i_seek == NO_SEEK && (unsigned int) position % block_size == 0 && (regular || mode_word == I_DIRECTORY)) { rdahed_inode = rip; rdahedpos = position; } rip->i_seek = NO_SEEK; if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ if (rdwt_err == END_OF_FILE) r = OK; if (r == OK) { if (rw_flag == READING) rip->i_update |= ATIME; if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME; rip->i_dirt = DIRTY; /* inode is thus now dirty */ } fs_m_out.RES_NBYTES = cum_io; return(r); }
/*===========================================================================* * fs_readwrite_s * *===========================================================================*/ PUBLIC int fs_readwrite_s(void) { int r, rw_flag, chunk, block_size, block_spec; int partial_cnt, regular, partial_pipe, nrbytes; cp_grant_id_t gid; off_t position, f_size, bytes_left; unsigned int off, cum_io; mode_t mode_word; int completed, r2 = OK; struct inode *rip; partial_pipe = 0; r = OK; /* Try to get inode according to its index */ if (fs_m_in.REQ_FD_INODE_INDEX >= 0 && fs_m_in.REQ_FD_INODE_INDEX < NR_INODES && inode[fs_m_in.REQ_FD_INODE_INDEX].i_num == fs_m_in.REQ_FD_INODE_NR) { rip = &inode[fs_m_in.REQ_FD_INODE_INDEX]; } else { /* Find the inode referred */ rip = find_inode(fs_dev, fs_m_in.REQ_FD_INODE_NR); if (!rip) { printf("FS: unavaliable inode by fs_readwrite(), nr: %d\n", fs_m_in.REQ_FD_INODE_NR); return EINVAL; } } mode_word = rip->i_mode & I_TYPE; regular = (mode_word == I_REGULAR || mode_word == I_NAMED_PIPE); block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0); /* Determine blocksize */ block_size = (block_spec ? get_block_size(rip->i_zone[0]) : rip->i_sp->s_block_size); f_size = (block_spec ? ULONG_MAX : rip->i_size); /* Get the values from the request message */ rw_flag = (fs_m_in.m_type == REQ_READ_S ? READING : WRITING); gid = fs_m_in.REQ_FD_GID; position = fs_m_in.REQ_FD_POS; nrbytes = (unsigned) fs_m_in.REQ_FD_NBYTES; /*partial_cnt = fs_m_in.REQ_FD_PARTIAL;*/ /*if (partial_cnt > 0) partial_pipe = 1;*/ rdwt_err = OK; /* set to EIO if disk error occurs */ if (rw_flag == WRITING && block_spec == 0) { /* Check in advance to see if file will grow too big. */ if (position > rip->i_sp->s_max_size - nrbytes) return(EFBIG); /* Clear the zone containing present EOF if hole about * to be created. This is necessary because all unwritten * blocks prior to the EOF must read as zeros. */ if (position > f_size) clear_zone(rip, f_size, 0); } cum_io = 0; /* Split the transfer into chunks that don't span two blocks. */ while (nrbytes != 0) { off = (unsigned int) (position % block_size);/* offset in blk*/ chunk = MIN(nrbytes, block_size - off); if (chunk < 0) chunk = block_size - off; if (rw_flag == READING) { bytes_left = f_size - position; if (position >= f_size) break; /* we are beyond EOF */ if (chunk > bytes_left) chunk = (int) bytes_left; } /* Read or write 'chunk' bytes. */ r = rw_chunk_s(rip, cvul64(position), off, chunk, (unsigned) nrbytes, rw_flag, gid, cum_io, block_size, &completed); if (r != OK) break; /* EOF reached */ if (rdwt_err < 0) break; /* Update counters and pointers. */ nrbytes -= chunk; /* bytes yet to be read */ cum_io += chunk; /* bytes read so far */ position += chunk; /* position within the file */ } fs_m_out.RES_FD_POS = position; /* It might change later and the VFS has to know this value */ /* On write, update file size and access time. */ if (rw_flag == WRITING) { if (regular || mode_word == I_DIRECTORY) { if (position > f_size) rip->i_size = position; } } else { if (rip->i_pipe == I_PIPE) { if ( position >= rip->i_size) { /* Reset pipe pointers. */ rip->i_size = 0; /* no data left */ position = 0; /* reset reader(s) */ } } } /* Check to see if read-ahead is called for, and if so, set it up. */ if (rw_flag == READING && rip->i_seek == NO_SEEK && position % block_size == 0 && (regular || mode_word == I_DIRECTORY)) { rdahed_inode = rip; rdahedpos = position; } rip->i_seek = NO_SEEK; if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ if (rdwt_err == END_OF_FILE) r = OK; /* if user-space copying failed, read/write failed. */ if (r == OK && r2 != OK) { r = r2; } if (r == OK) { if (rw_flag == READING) rip->i_update |= ATIME; if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME; rip->i_dirt = DIRTY; /* inode is thus now dirty */ } fs_m_out.RES_FD_CUM_IO = cum_io; fs_m_out.RES_FD_SIZE = rip->i_size; return(r); }
/*===========================================================================* * fs_getdents * *===========================================================================*/ ssize_t fs_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes, off_t *posp) { /* Retrieve directory entries. */ struct fsdriver_dentry fsdentry; struct inode *node, *child; const char *name; off_t pos; int r, skip, get_next, indexed; static char buf[GETDENTS_BUFSIZ]; if (*posp >= ULONG_MAX) return EIO; if ((node = find_inode(ino_nr)) == NULL) return EINVAL; indexed = node->i_indexed; get_next = FALSE; child = NULL; /* Call the getdents hook, if any, to "refresh" the directory. */ if (!is_inode_deleted(node) && vtreefs_hooks->getdents_hook != NULL) { r = vtreefs_hooks->getdents_hook(node, get_inode_cbdata(node)); if (r != OK) return r; } fsdriver_dentry_init(&fsdentry, data, bytes, buf, sizeof(buf)); do { /* Determine which inode and name to use for this entry. */ pos = (*posp)++; if (pos == 0) { /* The "." entry. */ child = node; name = "."; } else if (pos == 1) { /* The ".." entry. */ child = get_parent_inode(node); if (child == NULL) child = node; name = ".."; } else if (pos - 2 < indexed) { /* All indexed entries. */ child = get_inode_by_index(node, pos - 2); /* If there is no inode with this particular index, * continue with the next index number. */ if (child == NULL) continue; name = child->i_name; } else { /* All non-indexed entries. */ /* If this is the first loop iteration, first get to * the non-indexed child identified by the current * position. */ if (get_next == FALSE) { skip = pos - indexed - 2; child = get_first_inode(node); /* Skip indexed children. */ while (child != NULL && child->i_index != NO_INDEX) child = get_next_inode(child); /* Skip to the right position. */ while (child != NULL && skip-- > 0) child = get_next_inode(child); get_next = TRUE; } else { child = get_next_inode(child); } /* No more children? Then stop. */ if (child == NULL) break; assert(!is_inode_deleted(child)); name = child->i_name; } /* Add the directory entry to the output. */ r = fsdriver_dentry_add(&fsdentry, (ino_t) get_inode_number(child), name, strlen(name), IFTODT(child->i_stat.mode)); if (r < 0) return r; } while (r > 0); return fsdriver_dentry_finish(&fsdentry); }
/*===========================================================================* * fs_readwrite * *===========================================================================*/ PUBLIC int fs_readwrite(void) { int r, rw_flag, block_spec; int regular; cp_grant_id_t gid; off_t position, f_size, bytes_left; unsigned int off, cum_io, block_size, chunk; mode_t mode_word; int completed; struct inode *rip; size_t nrbytes; r = OK; /* Find the inode referred */ if ((rip = find_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); mode_word = rip->i_mode & I_TYPE; regular = (mode_word == I_REGULAR || mode_word == I_NAMED_PIPE); block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0); /* Determine blocksize */ if (block_spec) { block_size = get_block_size( (dev_t) rip->i_zone[0]); f_size = MAX_FILE_POS; } else { block_size = rip->i_sp->s_block_size; f_size = rip->i_size; } /* Get the values from the request message */ rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; position = (off_t) fs_m_in.REQ_SEEK_POS_LO; nrbytes = (size_t) fs_m_in.REQ_NBYTES; rdwt_err = OK; /* set to EIO if disk error occurs */ /* If this is file i/o, check we can write */ if (rw_flag == WRITING && !block_spec) { if(rip->i_sp->s_rd_only) return EROFS; /* Check in advance to see if file will grow too big. */ if (position > (off_t) (rip->i_sp->s_max_size - nrbytes)) return(EFBIG); /* Clear the zone containing present EOF if hole about * to be created. This is necessary because all unwritten * blocks prior to the EOF must read as zeros. */ if(position > f_size) clear_zone(rip, f_size, 0); } /* If this is block i/o, check we can write */ if(block_spec && rw_flag == WRITING && (dev_t) rip->i_zone[0] == superblock.s_dev && superblock.s_rd_only) return EROFS; cum_io = 0; /* Split the transfer into chunks that don't span two blocks. */ while (nrbytes > 0) { off = ((unsigned int) position) % block_size; /* offset in blk*/ chunk = min(nrbytes, block_size - off); if (rw_flag == READING) { bytes_left = f_size - position; if (position >= f_size) break; /* we are beyond EOF */ if (chunk > (unsigned int) bytes_left) chunk = bytes_left; } /* Read or write 'chunk' bytes. */ r = rw_chunk(rip, cvul64((unsigned long) position), off, chunk, nrbytes, rw_flag, gid, cum_io, block_size, &completed); if (r != OK) break; /* EOF reached */ if (rdwt_err < 0) break; /* Update counters and pointers. */ nrbytes -= chunk; /* bytes yet to be read */ cum_io += chunk; /* bytes read so far */ position += (off_t) chunk; /* position within the file */ } fs_m_out.RES_SEEK_POS_LO = position; /* It might change later and the VFS has to know this value */ /* On write, update file size and access time. */ if (rw_flag == WRITING) { if (regular || mode_word == I_DIRECTORY) { if (position > f_size) rip->i_size = position; } } rip->i_seek = NO_SEEK; if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ if (rdwt_err == END_OF_FILE) r = OK; /* even on a ROFS, writing to a device node on it is fine, * just don't update the inode stats for it. And dito for reading. */ if (r == OK && !rip->i_sp->s_rd_only) { if (rw_flag == READING) rip->i_update |= ATIME; if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME; IN_MARKDIRTY(rip); /* inode is thus now dirty */ } fs_m_out.RES_NBYTES = cum_io; return(r); }
/*===========================================================================* * fs_readwrite * *===========================================================================*/ PUBLIC int fs_readwrite(void) { int r, rw_flag, block_spec; int regular; cp_grant_id_t gid; off_t position, f_size, bytes_left; unsigned int off, cum_io, block_size, chunk; mode_t mode_word; int completed; struct inode *rip; size_t nrbytes; r = OK; /* Find the inode referred */ if ((rip = find_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); mode_word = rip->i_mode & I_TYPE; regular = (mode_word == I_REGULAR || mode_word == I_NAMED_PIPE); block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 : 0); /* Determine blocksize */ if (block_spec) { block_size = get_block_size( (dev_t) rip->i_block[0]); f_size = MAX_FILE_POS; } else { block_size = rip->i_sp->s_block_size; f_size = rip->i_size; if (f_size < 0) f_size = MAX_FILE_POS; } /* Get the values from the request message */ rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; position = (off_t) fs_m_in.REQ_SEEK_POS_LO; nrbytes = (size_t) fs_m_in.REQ_NBYTES; rdwt_err = OK; /* set to EIO if disk error occurs */ if (rw_flag == WRITING && !block_spec) { /* Check in advance to see if file will grow too big. */ if (position > (off_t) (rip->i_sp->s_max_size - nrbytes)) return(EFBIG); } cum_io = 0; /* Split the transfer into chunks that don't span two blocks. */ while (nrbytes != 0) { off = (unsigned int) (position % block_size);/* offset in blk*/ chunk = MIN(nrbytes, block_size - off); if (rw_flag == READING) { bytes_left = f_size - position; if (position >= f_size) break; /* we are beyond EOF */ if (chunk > bytes_left) chunk = (int) bytes_left; } /* Read or write 'chunk' bytes. */ r = rw_chunk(rip, cvul64((unsigned long) position), off, chunk, nrbytes, rw_flag, gid, cum_io, block_size, &completed); if (r != OK) break; /* EOF reached */ if (rdwt_err < 0) break; /* Update counters and pointers. */ nrbytes -= chunk; /* bytes yet to be read */ cum_io += chunk; /* bytes read so far */ position += (off_t) chunk; /* position within the file */ } fs_m_out.RES_SEEK_POS_LO = position; /* It might change later and the VFS has to know this value */ /* On write, update file size and access time. */ if (rw_flag == WRITING) { if (regular || mode_word == I_DIRECTORY) { if (position > f_size) rip->i_size = position; } } /* Check to see if read-ahead is called for, and if so, set it up. */ if(rw_flag == READING && rip->i_seek == NO_SEEK && (unsigned int) position % block_size == 0 && (regular || mode_word == I_DIRECTORY)) { rdahed_inode = rip; rdahedpos = position; } rip->i_seek = NO_SEEK; if (rdwt_err != OK) r = rdwt_err; /* check for disk error */ if (rdwt_err == END_OF_FILE) r = OK; if (r == OK) { if (rw_flag == READING) rip->i_update |= ATIME; if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME; rip->i_dirt = DIRTY; /* inode is thus now dirty */ } fs_m_out.RES_NBYTES = cum_io; return(r); }
/*===========================================================================* * do_create * *===========================================================================*/ PUBLIC int do_create() { /* Create a new file. */ char path[PATH_MAX], name[NAME_MAX+1]; struct inode *parent, *ino; struct hgfs_attr attr; hgfs_file_t handle; int r; /* We cannot create files on a read-only file system. */ if (state.read_only) return EROFS; /* Get path, name, parent inode and possibly inode for the given path. */ if ((r = get_name(m_in.REQ_GRANT, m_in.REQ_PATH_LEN, name)) != OK) return r; if (!strcmp(name, ".") || !strcmp(name, "..")) return EEXIST; if ((parent = find_inode(m_in.REQ_INODE_NR)) == NULL) return EINVAL; if ((r = verify_dentry(parent, name, path, &ino)) != OK) return r; /* Are we going to need a new inode upon success? * Then make sure there is one available before trying anything. */ if (ino == NULL || ino->i_ref > 1 || HAS_CHILDREN(ino)) { if (!have_free_inode()) { if (ino != NULL) put_inode(ino); return ENFILE; } } /* Perform the actual create call. */ r = hgfs_open(path, O_CREAT | O_EXCL | O_RDWR, m_in.REQ_MODE, &handle); if (r != OK) { /* Let's not try to be too clever with error codes here. If something * is wrong with the directory, we'll find out later anyway. */ if (ino != NULL) put_inode(ino); return r; } /* Get the created file's attributes. */ attr.a_mask = HGFS_ATTR_MODE | HGFS_ATTR_SIZE; r = hgfs_getattr(path, &attr); /* If this fails, or returns a directory, we have a problem. This * scenario is in fact possible with race conditions. * Simulate a close and return a somewhat appropriate error. */ if (r != OK || S_ISDIR(attr.a_mode)) { printf("HGFS: lost file after creation!\n"); hgfs_close(handle); if (ino != NULL) { del_dentry(ino); put_inode(ino); } return (r == OK) ? EEXIST : r; } /* We do assume that the HGFS open(O_CREAT|O_EXCL) did its job. * If we previousy found an inode, get rid of it now. It's old. */ if (ino != NULL) { del_dentry(ino); put_inode(ino); } /* Associate the open file handle with an inode, and reply with its details. */ ino = get_free_inode(); assert(ino != NULL); /* we checked before whether we had a free one */ ino->i_file = handle; ino->i_flags = I_HANDLE; add_dentry(parent, name, ino); m_out.RES_INODE_NR = INODE_NR(ino); m_out.RES_MODE = get_mode(ino, attr.a_mode); m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size); m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size); m_out.RES_UID = opt.uid; m_out.RES_GID = opt.gid; m_out.RES_DEV = NO_DEV; return OK; }
/*===========================================================================* * fs_getdents * *===========================================================================*/ int fs_getdents(void) { /* Retrieve directory entries. */ struct inode *node, *child = NULL; struct dirent *dent; char *name; size_t len, off, user_off, user_left; off_t pos; int r, skip, get_next, indexed; static char buf[GETDENTS_BUFSIZ]; if (fs_m_in.REQ_SEEK_POS_HI != 0) return EIO; if ((node = find_inode(fs_m_in.REQ_INODE_NR)) == NULL) return EINVAL; off = 0; user_off = 0; user_left = fs_m_in.REQ_MEM_SIZE; indexed = node->i_indexed; get_next = FALSE; child = NULL; /* Call the getdents hook, if any, to "refresh" the directory. */ if (!is_inode_deleted(node) && vtreefs_hooks->getdents_hook != NULL) { r = vtreefs_hooks->getdents_hook(node, get_inode_cbdata(node)); if (r != OK) return r; } for (pos = fs_m_in.REQ_SEEK_POS_LO; ; pos++) { /* Determine which inode and name to use for this entry. */ if (pos == 0) { /* The "." entry. */ child = node; name = "."; } else if (pos == 1) { /* The ".." entry. */ child = get_parent_inode(node); if (child == NULL) child = node; name = ".."; } else if (pos - 2 < indexed) { /* All indexed entries. */ child = get_inode_by_index(node, pos - 2); /* If there is no inode with this particular index, * continue with the next index number. */ if (child == NULL) continue; name = child->i_name; } else { /* All non-indexed entries. */ /* If this is the first loop iteration, first get to * the non-indexed child identified by the current * position. */ if (get_next == FALSE) { skip = pos - indexed - 2; child = get_first_inode(node); /* Skip indexed children. */ while (child != NULL && child->i_index != NO_INDEX) child = get_next_inode(child); /* Skip to the right position. */ while (child != NULL && skip-- > 0) child = get_next_inode(child); get_next = TRUE; } else { child = get_next_inode(child); } /* No more children? Then stop. */ if (child == NULL) break; assert(!is_inode_deleted(child)); name = child->i_name; } len = DWORD_ALIGN(sizeof(struct dirent) + strlen(name)); /* Is the user buffer too small to store another record? */ if (user_off + off + len > user_left) { /* Is the user buffer too small for even a single * record? */ if (user_off == 0 && off == 0) return EINVAL; break; } /* If our own buffer cannot contain the new record, copy out * first. */ if (off + len > sizeof(buf)) { r = sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT, user_off, (vir_bytes) buf, off, D); if (r != OK) return r; user_off += off; user_left -= off; off = 0; } /* Fill in the actual directory entry. */ dent = (struct dirent *) &buf[off]; dent->d_ino = get_inode_number(child); dent->d_off = pos; dent->d_reclen = len; strcpy(dent->d_name, name); off += len; } /* If there is anything left in our own buffer, copy that out now. */ if (off > 0) { r = sys_safecopyto(fs_m_in.m_source, fs_m_in.REQ_GRANT, user_off, (vir_bytes) buf, off, D); if (r != OK) return r; user_off += off; } fs_m_out.RES_SEEK_POS_HI = 0; fs_m_out.RES_SEEK_POS_LO = pos; fs_m_out.RES_NBYTES = user_off; return OK; }
/*===========================================================================* * do_getdents * *===========================================================================*/ int do_getdents() { /* Retrieve directory entries. */ char name[NAME_MAX+1]; struct inode *ino, *child; struct dirent *dent; struct sffs_attr attr; size_t len, off, user_off, user_left; off_t pos; int r; /* must be at least sizeof(struct dirent) + NAME_MAX */ static char buf[BLOCK_SIZE]; attr.a_mask = SFFS_ATTR_MODE; if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL) return EINVAL; if (m_in.REQ_SEEK_POS_HI != 0) return EINVAL; if (!IS_DIR(ino)) return ENOTDIR; /* We are going to need at least one free inode to store children in. */ if (!have_free_inode()) return ENFILE; /* If we don't have a directory handle yet, get one now. */ if ((r = get_handle(ino)) != OK) return r; off = 0; user_off = 0; user_left = m_in.REQ_MEM_SIZE; /* We use the seek position as file index number. The first position is for * the "." entry, the second position is for the ".." entry, and the next * position numbers each represent a file in the directory. */ for (pos = m_in.REQ_SEEK_POS_LO; ; pos++) { /* Determine which inode and name to use for this entry. * We have no idea whether the host will give us "." and/or "..", * so generate our own and skip those from the host. */ if (pos == 0) { /* Entry for ".". */ child = ino; strcpy(name, "."); get_inode(child); } else if (pos == 1) { /* Entry for "..", but only when there is a parent. */ if (ino->i_parent == NULL) continue; child = ino->i_parent; strcpy(name, ".."); get_inode(child); } else { /* Any other entry, not being "." or "..". */ r = sffs_table->t_readdir(ino->i_dir, pos - 2, name, sizeof(name), &attr); if (r != OK) { /* No more entries? Then close the handle and stop. */ if (r == ENOENT) { put_handle(ino); break; } /* FIXME: what if the error is ENAMETOOLONG? */ return r; } if (!strcmp(name, ".") || !strcmp(name, "..")) continue; if ((child = lookup_dentry(ino, name)) == NULL) { child = get_free_inode(); /* We were promised a free inode! */ assert(child != NULL); child->i_flags = MODE_TO_DIRFLAG(attr.a_mode); add_dentry(ino, name, child); } } len = DWORD_ALIGN(sizeof(struct dirent) + strlen(name)); /* Is the user buffer too small to store another record? * Note that we will be rerequesting the same dentry upon a subsequent * getdents call this way, but we really need the name length for this. */ if (user_off + off + len > user_left) { put_inode(child); /* Is the user buffer too small for even a single record? */ if (user_off == 0 && off == 0) return EINVAL; break; } /* If our own buffer cannot contain the new record, copy out first. */ if (off + len > sizeof(buf)) { r = sys_safecopyto(m_in.m_source, m_in.REQ_GRANT, user_off, (vir_bytes) buf, off, D); if (r != OK) { put_inode(child); return r; } user_off += off; user_left -= off; off = 0; } /* Fill in the actual directory entry. */ dent = (struct dirent *) &buf[off]; dent->d_ino = INODE_NR(child); dent->d_off = pos; dent->d_reclen = len; strcpy(dent->d_name, name); off += len; put_inode(child); } /* If there is anything left in our own buffer, copy that out now. */ if (off > 0) { r = sys_safecopyto(m_in.m_source, m_in.REQ_GRANT, user_off, (vir_bytes) buf, off, D); if (r != OK) return r; user_off += off; } m_out.RES_SEEK_POS_HI = 0; m_out.RES_SEEK_POS_LO = pos; m_out.RES_NBYTES = user_off; return OK; }
int main(int argc, char **argv) { if(argc != 4) { fprintf(stderr, "Usage: ext2_cp <image file name> <Absolute path on the disk image> <Absolute on the disk image>\n"); exit(1); } int fd = open(argv[1], O_RDWR); if (!fd) { fprintf(stderr, "no file\n" ); exit(1); } disk = mmap(NULL, 128 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if(disk == MAP_FAILED) { perror("mmap"); exit(1); } char *abs_path = argv[2]; if (abs_path[0] != '/') { fprintf(stderr,"Not an Absolute Path" ); } char *link_from[100]; int length=0; char *tok = strtok(abs_path, "/"); while (tok != NULL) { link_from[length]= tok; length++; tok = strtok(NULL, "/"); } abs_path = argv[3]; char *link_to[100]; int length2=0; char *tok2 = strtok(abs_path, "/"); while (tok2 != NULL) { link_to[length2]= tok2; length2++; tok2 = strtok(NULL, "/"); } blockgd = (struct ext2_group_desc *)(disk + 1024 + (EXT2_BLOCK_SIZE)); inodeTable = (struct ext2_inode *)(disk + (blockgd->bg_inode_table * (EXT2_BLOCK_SIZE))); int inode = 1; int i; for (i = 0; i< length-1; i++) { inode = find_inode(link_from[i], inode); if (inode == -1) { fprintf(stderr, "no such directory\n"); exit(ENOENT); } } int inode2 = 1; for (i = 0; i< length2-1; i++) { inode2 = find_inode(link_to[i], inode2); if (inode2 == -1) { fprintf(stderr, "no such directory\n"); exit(ENOENT); } } struct ext2_inode dirInode = inodeTable[inode]; int fileInode = -1; int shift=0; for(i=0; i<dirInode.i_blocks/2; i++) { if(fileInode!=-1) { break; } struct ext2_dir_entry_2 *entry; if(i>=12) { entry = (struct ext2_dir_entry_2 *)(disk + (((unsigned int *)(disk + (inodeTable[inode].i_block[12] -1) * (EXT2_BLOCK_SIZE)))[i-12] -1)*EXT2_BLOCK_SIZE); } else { entry = (struct ext2_dir_entry_2 *)(disk + inodeTable[inode].i_block[i] * (EXT2_BLOCK_SIZE)); } while (shift < EXT2_BLOCK_SIZE) { char name[entry->name_len]; int n; for(n= 0; n < entry->name_len; n++) { name[n]=entry->name[n]; } name[entry->name_len] ='\0'; if (strcmp(link_from[length - 1], name) == 0) { if(entry->file_type == 1) { fileInode = entry->inode -1; // -1 cause position in the inode table break; } else { printf("link from is not a file\n"); exit(EISDIR); } } else { shift=shift + entry->rec_len; entry = (struct ext2_dir_entry_2 *)(disk + inodeTable[inode].i_block[i] * (EXT2_BLOCK_SIZE)+ shift); } } } dirInode = inodeTable[inode2]; int file2Inode = -1; shift = 0; for(i=0; i<dirInode.i_blocks/2; i++) { if(file2Inode!=-1) { break; } struct ext2_dir_entry_2 *entry; if(i>=12) { entry = (struct ext2_dir_entry_2 *)(disk + (((unsigned int *)(disk + (inodeTable[inode2].i_block[12] -1) * (EXT2_BLOCK_SIZE)))[i-12] -1)*EXT2_BLOCK_SIZE); } else { entry = (struct ext2_dir_entry_2 *)(disk + inodeTable[inode2].i_block[i] * (EXT2_BLOCK_SIZE)); } while (shift < EXT2_BLOCK_SIZE) { char name[entry->name_len]; int n; for(n= 0; n < entry->name_len; n++) { name[n]=entry->name[n]; } name[entry->name_len] ='\0'; if (strcmp(link_to[length - 1], name) == 0) { if(entry->file_type == 1) { file2Inode = entry->inode -1; // -1 cause position in the inode table break; } else { printf("link from is not a file\n"); exit(EISDIR); } } else { shift=shift + entry->rec_len; entry = (struct ext2_dir_entry_2 *)(disk + inodeTable[inode2].i_block[i] * (EXT2_BLOCK_SIZE)+ shift); } } } printf("file1: %d\n",fileInode); printf("file2: %d\n",file2Inode); return 0; }
/*===========================================================================* * do_getdents * *===========================================================================*/ ssize_t do_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes, off_t *posp) { /* Retrieve directory entries. */ struct fsdriver_dentry fsdentry; char name[NAME_MAX+1]; struct inode *ino, *child; struct sffs_attr attr; off_t pos; int r; /* must be at least sizeof(struct dirent) + NAME_MAX */ static char buf[BLOCK_SIZE]; if ((ino = find_inode(ino_nr)) == NULL) return EINVAL; if (!IS_DIR(ino)) return ENOTDIR; if (*posp < 0 || *posp >= ULONG_MAX) return EINVAL; /* We are going to need at least one free inode to store children in. */ if (!have_free_inode()) return ENFILE; /* If we don't have a directory handle yet, get one now. */ if ((r = get_handle(ino)) != OK) return r; fsdriver_dentry_init(&fsdentry, data, bytes, buf, sizeof(buf)); /* We use the seek position as file index number. The first position is for * the "." entry, the second position is for the ".." entry, and the next * position numbers each represent a file in the directory. */ do { /* Determine which inode and name to use for this entry. * We have no idea whether the host will give us "." and/or "..", * so generate our own and skip those from the host. */ pos = (*posp)++; if (pos == 0) { /* Entry for ".". */ child = ino; strcpy(name, "."); get_inode(child); } else if (pos == 1) { /* Entry for "..", but only when there is a parent. */ if (ino->i_parent == NULL) continue; child = ino->i_parent; strcpy(name, ".."); get_inode(child); } else { /* Any other entry, not being "." or "..". */ attr.a_mask = SFFS_ATTR_MODE; r = sffs_table->t_readdir(ino->i_dir, pos - 2, name, sizeof(name), &attr); if (r != OK) { /* No more entries? Then close the handle and stop. */ if (r == ENOENT) { put_handle(ino); break; } /* FIXME: what if the error is ENAMETOOLONG? */ return r; } if (!strcmp(name, ".") || !strcmp(name, "..")) continue; if ((child = lookup_dentry(ino, name)) == NULL) { child = get_free_inode(); /* We were promised a free inode! */ assert(child != NULL); child->i_flags = MODE_TO_DIRFLAG(attr.a_mode); add_dentry(ino, name, child); } } r = fsdriver_dentry_add(&fsdentry, INODE_NR(child), name, strlen(name), IS_DIR(child) ? DT_DIR : DT_REG); put_inode(child); if (r < 0) return r; } while (r > 0); return fsdriver_dentry_finish(&fsdentry); }
/*===========================================================================* * fs_readwrite * *===========================================================================*/ ssize_t fs_readwrite(ino_t ino_nr, struct fsdriver_data *data, size_t nrbytes, off_t position, int call) { int r; int regular; off_t f_size, bytes_left; size_t off, cum_io, block_size, chunk; mode_t mode_word; int completed; struct inode *rip; r = OK; /* Find the inode referred */ if ((rip = find_inode(fs_dev, ino_nr)) == NULL) return(EINVAL); mode_word = rip->i_mode & I_TYPE; regular = (mode_word == I_REGULAR); /* Determine blocksize */ block_size = rip->i_sp->s_block_size; f_size = rip->i_size; lmfs_reset_rdwt_err(); /* If this is file i/o, check we can write */ if (call == FSC_WRITE) { if(rip->i_sp->s_rd_only) return EROFS; /* Check in advance to see if file will grow too big. */ if (position > (off_t) (rip->i_sp->s_max_size - nrbytes)) return(EFBIG); /* Clear the zone containing present EOF if hole about * to be created. This is necessary because all unwritten * blocks prior to the EOF must read as zeros. */ if(position > f_size) clear_zone(rip, f_size, 0); } cum_io = 0; /* Split the transfer into chunks that don't span two blocks. */ while (nrbytes > 0) { off = ((unsigned int) position) % block_size; /* offset in blk*/ chunk = block_size - off; if (chunk > nrbytes) chunk = nrbytes; if (call == FSC_READ) { bytes_left = f_size - position; if (position >= f_size) break; /* we are beyond EOF */ if (chunk > (unsigned int) bytes_left) chunk = bytes_left; } /* Read or write 'chunk' bytes. */ r = rw_chunk(rip, ((u64_t)((unsigned long)position)), off, chunk, nrbytes, call, data, cum_io, block_size, &completed); if (r != OK) break; /* EOF reached */ if (lmfs_rdwt_err() < 0) break; /* Update counters and pointers. */ nrbytes -= chunk; /* bytes yet to be read */ cum_io += chunk; /* bytes read so far */ position += (off_t) chunk; /* position within the file */ } /* On write, update file size and access time. */ if (call == FSC_WRITE) { if (regular || mode_word == I_DIRECTORY) { if (position > f_size) rip->i_size = position; } } rip->i_seek = NO_SEEK; if (lmfs_rdwt_err() != OK) r = lmfs_rdwt_err(); /* check for disk error */ if (lmfs_rdwt_err() == END_OF_FILE) r = OK; if (r != OK) return r; /* even on a ROFS, writing to a device node on it is fine, * just don't update the inode stats for it. And dito for reading. */ if (!rip->i_sp->s_rd_only) { if (call == FSC_READ) rip->i_update |= ATIME; if (call == FSC_WRITE) rip->i_update |= CTIME | MTIME; IN_MARKDIRTY(rip); /* inode is thus now dirty */ } return cum_io; }
/*===========================================================================* * fs_readwrite * *===========================================================================*/ int fs_readwrite(void) { int r, rw_flag; block_t b; struct buf *bp; cp_grant_id_t gid; off_t position, f_size; unsigned int nrbytes, cum_io; mode_t mode_word; struct pipe_inode *rip; ino_t inumb; r = 0; cum_io = 0; inumb = fs_m_in.REQ_INODE_NR; rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); #if 0 printk("PFS: going to %s inode %d\n", (rw_flag == READING? "read from": "write to"), inumb); #endif /* Find the inode referred */ if ((rip = find_inode(inumb)) == NIL_INODE) return(-EINVAL); mode_word = rip->i_mode & I_TYPE; if (mode_word != I_NAMED_PIPE) return(-EIO); f_size = rip->i_size; /* Get the values from the request message */ rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING); gid = fs_m_in.REQ_GRANT; position = fs_m_in.REQ_SEEK_POS_LO; nrbytes = (unsigned) fs_m_in.REQ_NBYTES; if (rw_flag == WRITING) { /* Check in advance to see if file will grow too big. */ if (position > PIPE_BUF - nrbytes) return(-EFBIG); } /* Mark inode in use */ if ((get_inode(rip->i_dev, rip->i_num)) == NIL_INODE) return(err_code); if ((bp = get_block(rip->i_dev, rip->i_num)) == NIL_BUF) return(err_code); if (rw_flag == READING) { /* Copy a chunk from the block buffer to user space. */ r = sys_safecopyto(VFS_PROC_NR, gid, 0, (vir_bytes) (bp->b_data+position), (phys_bytes) nrbytes, D); } else { /* Copy a chunk from user space to the block buffer. */ r = sys_safecopyfrom(VFS_PROC_NR, gid, 0, (vir_bytes) (bp->b_data+position), (phys_bytes) nrbytes, D); } if (r == 0) { position += nrbytes; /* Update position */ cum_io += nrbytes; } fs_m_out.RES_SEEK_POS_LO = position; /* It might change later and the VFS has to know this value */ /* On write, update file size and access time. */ if (rw_flag == WRITING) { if (position > f_size) rip->i_size = position; } else { if(position >= rip->i_size) { /* All data in the pipe is read, so reset pipe pointers */ rip->i_size = 0; /* no data left */ position = 0; /* reset reader(s) */ } } bp->b_bytes = position; if (rw_flag == READING) rip->i_update |= ATIME; if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME; fs_m_out.RES_NBYTES = cum_io; put_inode(rip); put_block(rip->i_dev, rip->i_num); return(r); }
int altera_ci_init(struct altera_ci_config *config, int ci_nr) { struct altera_ci_state *state; struct fpga_inode *temp_int = find_inode(config->dev); struct fpga_internal *inter = NULL; int ret = 0; u8 store = 0; state = kzalloc(sizeof(struct altera_ci_state), GFP_KERNEL); ci_dbg_print("%s\n", __func__); if (!state) { ret = -ENOMEM; goto err; } if (temp_int != NULL) { inter = temp_int->internal; (inter->cis_used)++; ci_dbg_print("%s: Find Internal Structure!\n", __func__); } else { inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); if (!inter) { ret = -ENOMEM; goto err; } temp_int = append_internal(inter); inter->cis_used = 1; inter->dev = config->dev; inter->fpga_rw = config->fpga_rw; mutex_init(&inter->fpga_mutex); inter->strt_wrk = 1; ci_dbg_print("%s: Create New Internal Structure!\n", __func__); } ci_dbg_print("%s: setting state = %p for ci = %d\n", __func__, state, ci_nr - 1); inter->state[ci_nr - 1] = state; state->internal = inter; state->nr = ci_nr - 1; state->ca.owner = THIS_MODULE; state->ca.read_attribute_mem = altera_ci_read_attribute_mem; state->ca.write_attribute_mem = altera_ci_write_attribute_mem; state->ca.read_cam_control = altera_ci_read_cam_ctl; state->ca.write_cam_control = altera_ci_write_cam_ctl; state->ca.slot_reset = altera_ci_slot_reset; state->ca.slot_shutdown = altera_ci_slot_shutdown; state->ca.slot_ts_enable = altera_ci_slot_ts_ctl; state->ca.poll_slot_status = altera_poll_ci_slot_status; state->ca.data = state; ret = dvb_ca_en50221_init(config->adapter, &state->ca, /* flags */ 0, /* n_slots */ 1); if (0 != ret) goto err; altera_hw_filt_init(config, ci_nr); if (inter->strt_wrk) { INIT_WORK(&inter->work, netup_read_ci_status); inter->strt_wrk = 0; } ci_dbg_print("%s: CI initialized!\n", __func__); mutex_lock(&inter->fpga_mutex); /* Enable div */ netup_fpga_op_rw(inter, NETUP_CI_TSA_DIV, 0x0, 0); netup_fpga_op_rw(inter, NETUP_CI_TSB_DIV, 0x0, 0); /* enable TS out */ store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD); store |= (3 << 4); netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); ret = netup_fpga_op_rw(inter, NETUP_CI_REVISION, 0, NETUP_CI_FLG_RD); /* enable irq */ netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0x44, 0); mutex_unlock(&inter->fpga_mutex); ci_dbg_print("%s: NetUP CI Revision = 0x%x\n", __func__, ret); schedule_work(&inter->work); return 0; err: ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret); kfree(state); return ret; }
int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) { struct netup_hw_pid_filter *pid_filt = NULL; struct fpga_inode *temp_int = find_inode(config->dev); struct fpga_internal *inter = NULL; int ret = 0; pid_filt = kzalloc(sizeof(struct netup_hw_pid_filter), GFP_KERNEL); ci_dbg_print("%s\n", __func__); if (!pid_filt) { ret = -ENOMEM; goto err; } if (temp_int != NULL) { inter = temp_int->internal; (inter->filts_used)++; ci_dbg_print("%s: Find Internal Structure!\n", __func__); } else { inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); if (!inter) { ret = -ENOMEM; goto err; } temp_int = append_internal(inter); inter->filts_used = 1; inter->dev = config->dev; inter->fpga_rw = config->fpga_rw; mutex_init(&inter->fpga_mutex); inter->strt_wrk = 1; ci_dbg_print("%s: Create New Internal Structure!\n", __func__); } ci_dbg_print("%s: setting hw pid filter = %p for ci = %d\n", __func__, pid_filt, hw_filt_nr - 1); inter->pid_filt[hw_filt_nr - 1] = pid_filt; pid_filt->demux = config->demux; pid_filt->internal = inter; pid_filt->nr = hw_filt_nr - 1; /* store old feed controls */ pid_filt->start_feed = config->demux->start_feed; pid_filt->stop_feed = config->demux->stop_feed; /* replace with new feed controls */ if (hw_filt_nr == 1) { pid_filt->demux->start_feed = altera_ci_start_feed_1; pid_filt->demux->stop_feed = altera_ci_stop_feed_1; } else if (hw_filt_nr == 2) { pid_filt->demux->start_feed = altera_ci_start_feed_2; pid_filt->demux->stop_feed = altera_ci_stop_feed_2; } altera_toggle_fullts_streaming(pid_filt, 0, 1); return 0; err: ci_dbg_print("%s: Can't init hardware filter: Error %d\n", __func__, ret); kfree(pid_filt); return ret; }
int main(int argc, char **argv){ if(argc != 3) { fprintf(stderr, "Usage: ext2_ls <image file name> <absolute path on the disk>\n"); exit(1); } int fd = open(argv[1], O_RDWR); disk = mmap(NULL, 128 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if(disk == MAP_FAILED) { perror("mmap"); exit(1); } char *abs_path = argv[2]; if (abs_path[0] != '/') { fprintf(stderr,"Not an Absolute Path" ); exit(1); } char *dir[100]; int length=0; char *tok = strtok(abs_path, "/"); while (tok != NULL) { dir[length]= tok; length++; tok = strtok(NULL, "/"); } blockgd = (struct ext2_group_desc *)(disk + 1024 + (EXT2_BLOCK_SIZE)); inodeTable = (struct ext2_inode *)(disk + (blockgd->bg_inode_table * (EXT2_BLOCK_SIZE))); int inode = 1; int i; for (i = 0; i< length-1; i++) { inode = find_inode(dir[i], inode); if (inode == -1) { fprintf(stderr, "no such directory\n"); exit(ENOENT); } } struct ext2_inode dirInode = inodeTable[inode]; int fileInode = -1; int shift=0; for(i=0;i<dirInode.i_blocks/2;i++){ if(fileInode!=-1){ break; } struct ext2_dir_entry_2 *entry; if(i>=12){ entry = (struct ext2_dir_entry_2 *)(disk + (((unsigned int *)(disk + (inodeTable[inode].i_block[12] -1) * (EXT2_BLOCK_SIZE)))[i-12] -1)*EXT2_BLOCK_SIZE); }else{ entry = (struct ext2_dir_entry_2 *)(disk + inodeTable[inode].i_block[i] * (EXT2_BLOCK_SIZE)); } struct ext2_dir_entry_2 *prev; while (shift < EXT2_BLOCK_SIZE) { char name[entry->name_len]; int n; for(n= 0; n < entry->name_len; n++) { name[n]=entry->name[n]; } name[entry->name_len] ='\0'; if (entry->file_type == 1 && strcmp(dir[length - 1], name) == 0) { fileInode = entry->inode -1; // -1 cause position in the inode table if(prev){ prev->rec_len += entry->rec_len; } break; } else { shift=shift + entry->rec_len; prev = entry; entry = (struct ext2_dir_entry_2 *)(disk + inodeTable[inode].i_block[i] * (EXT2_BLOCK_SIZE)+ shift); } } } if(fileInode!=-1){ struct ext2_inode fileInodeStruct = inodeTable[fileInode]; int j; for(j=0;j<fileInodeStruct.i_blocks/2;j++){ int blockID; if(j>=12){ blockID = (disk + (fileInodeStruct.i_block[12] -1)*EXT2_BLOCK_SIZE)[j-12] -1; }else{ blockID = fileInodeStruct.i_block[j] - 1; } unset_bit(blockgd->bg_block_bitmap, blockID); } unset_bit(blockgd->bg_inode_bitmap, fileInode); }else{ printf("no such file"); exit(ENOENT); } return 0; }