/*===========================================================================* * new_node * *===========================================================================*/ PRIVATE struct inode *new_node(struct inode **ldirp, char *path, mode_t bits, zone_t z0, int opaque, char *parsed) { /* New_node() is called by common_open(), do_mknod(), and do_mkdir(). * In all cases it allocates a new inode, makes a directory entry for it on * the path 'path', and initializes it. It returns a pointer to the inode if * it can do this; otherwise it returns NIL_INODE. It always sets 'err_code' * to an appropriate value (OK or an error code). * * The parsed path rest is returned in 'parsed' if parsed is nonzero. It * has to hold at least NAME_MAX bytes. */ register struct inode *rip; register int r; char string[NAME_MAX]; *ldirp = parse_path(path, string, opaque ? LAST_DIR : LAST_DIR_EATSYM); if (*ldirp == NIL_INODE) return(NIL_INODE); /* The final directory is accessible. Get final component of the path. */ rip = advance(ldirp, string); if (S_ISDIR(bits) && (*ldirp)->i_nlinks >= ((*ldirp)->i_sp->s_version == V1 ? CHAR_MAX : SHRT_MAX)) { /* New entry is a directory, alas we can't give it a ".." */ put_inode(rip); err_code = EMLINK; return(NIL_INODE); } if ( rip == NIL_INODE && err_code == ENOENT) { /* Last path component does not exist. Make new directory entry. */ if ( (rip = alloc_inode((*ldirp)->i_dev, bits)) == NIL_INODE) { /* Can't creat new inode: out of inodes. */ return(NIL_INODE); } /* Force inode to the disk before making directory entry to make * the system more robust in the face of a crash: an inode with * no directory entry is much better than the opposite. */ rip->i_nlinks++; rip->i_zone[0] = z0; /* major/minor device numbers */ rw_inode(rip, WRITING); /* force inode to disk now */ /* New inode acquired. Try to make directory entry. */ if ((r = search_dir(*ldirp, string, &rip->i_num,ENTER)) != OK) { rip->i_nlinks--; /* pity, have to free disk inode */ rip->i_dirt = DIRTY; /* dirty inodes are written out */ put_inode(rip); /* this call frees the inode */ err_code = r; return(NIL_INODE); } } else { /* Either last component exists, or there is some problem. */ if (rip != NIL_INODE) r = EEXIST; else r = err_code; } if(parsed) { /* Give the caller the parsed string if requested. */ strncpy(parsed, string, NAME_MAX-1); parsed[NAME_MAX-1] = '\0'; } /* The caller has to return the directory inode (*ldirp). */ err_code = r; return(rip); }
/*===========================================================================* * do_close * *===========================================================================*/ PUBLIC int do_close() { /* Perform the close(fd) system call. */ register struct filp *rfilp; register struct inode *rip; struct file_lock *flp; int rw, mode_word, lock_count; dev_t dev; /* First locate the inode that belongs to the file descriptor. */ if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code); rip = rfilp->filp_ino; /* 'rip' points to the inode */ if (rfilp->filp_count - 1 == 0 && rfilp->filp_mode != FILP_CLOSED) { /* Check to see if the file is special. */ mode_word = rip->i_mode & I_TYPE; if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) { dev = (dev_t) rip->i_zone[0]; if (mode_word == I_BLOCK_SPECIAL) { /* Invalidate cache entries unless special is mounted * or ROOT */ if (!mounted(rip)) { (void) do_sync(); /* purge cache */ invalidate(dev); } } /* Do any special processing on device close. */ dev_close(dev); } } /* If the inode being closed is a pipe, release everyone hanging on it. */ if (rip->i_pipe == I_PIPE) { rw = (rfilp->filp_mode & R_BIT ? WRITE : READ); release(rip, rw, NR_PROCS); } /* If a write has been done, the inode is already marked as DIRTY. */ if (--rfilp->filp_count == 0) { if (rip->i_pipe == I_PIPE && rip->i_count > 1) { /* Save the file position in the i-node in case needed later. * The read and write positions are saved separately. The * last 3 zones in the i-node are not used for (named) pipes. */ if (rfilp->filp_mode == R_BIT) rip->i_zone[V2_NR_DZONES+0] = (zone_t) rfilp->filp_pos; else rip->i_zone[V2_NR_DZONES+1] = (zone_t) rfilp->filp_pos; } put_inode(rip); } fp->fp_cloexec &= ~(1L << m_in.fd); /* turn off close-on-exec bit */ fp->fp_filp[m_in.fd] = NIL_FILP; FD_CLR(m_in.fd, &fp->fp_filp_inuse); /* Check to see if the file is locked. If so, release all locks. */ if (nr_locks == 0) return(OK); lock_count = nr_locks; /* save count of locks */ for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) { if (flp->lock_type == 0) continue; /* slot not in use */ if (flp->lock_inode == rip && flp->lock_pid == fp->fp_pid) { flp->lock_type = 0; nr_locks--; } } if (nr_locks < lock_count) lock_revive(); /* lock released */ return(OK); }
/*===========================================================================* * fs_readsuper * *===========================================================================*/ PUBLIC int fs_readsuper() { /* This function reads the superblock of the partition, gets the root inode * and sends back the details of them. Note, that the FS process does not * know the index of the vmnt object which refers to it, whenever the pathname * lookup leaves a partition an ELEAVEMOUNT error is transferred back * so that the VFS knows that it has to find the vnode on which this FS * process' partition is mounted on. */ struct inode *root_ip; cp_grant_id_t label_gid; size_t label_len; int r; endpoint_t driver_e; int readonly, isroot; fs_dev = (dev_t) fs_m_in.REQ_DEV; label_gid = (cp_grant_id_t) fs_m_in.REQ_GRANT; label_len = (size_t) fs_m_in.REQ_PATH_LEN; readonly = (fs_m_in.REQ_FLAGS & REQ_RDONLY) ? 1 : 0; isroot = (fs_m_in.REQ_FLAGS & REQ_ISROOT) ? 1 : 0; if (label_len > sizeof(fs_dev_label)) return(EINVAL); r = sys_safecopyfrom(fs_m_in.m_source, label_gid, (vir_bytes) 0, (vir_bytes) fs_dev_label, label_len, D); if (r != OK) { printf("MFS %s:%d safecopyfrom failed: %d\n", __FILE__, __LINE__, r); return(EINVAL); } r = ds_retrieve_label_endpt(fs_dev_label, &driver_e); if (r != OK) { printf("MFS %s:%d ds_retrieve_label_endpt failed for '%s': %d\n", __FILE__, __LINE__, fs_dev_label, r); return(EINVAL); } /* Map the driver endpoint for this major */ bdev_driver(fs_dev, driver_e); /* Open the device the file system lives on. */ if (bdev_open(fs_dev, readonly ? R_BIT : (R_BIT|W_BIT) ) != OK) { return(EINVAL); } /* Fill in the super block. */ superblock.s_dev = fs_dev; /* read_super() needs to know which dev */ r = read_super(&superblock); /* Is it recognized as a Minix filesystem? */ if (r != OK) { superblock.s_dev = NO_DEV; bdev_close(fs_dev); return(r); } set_blocksize(&superblock); /* Get the root inode of the mounted file system. */ if( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) { printf("MFS: couldn't get root inode\n"); superblock.s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } if(root_ip->i_mode == 0) { printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__); put_inode(root_ip); superblock.s_dev = NO_DEV; bdev_close(fs_dev); return(EINVAL); } superblock.s_rd_only = readonly; superblock.s_is_root = isroot; /* Root inode properties */ fs_m_out.RES_INODE_NR = root_ip->i_num; fs_m_out.RES_MODE = root_ip->i_mode; fs_m_out.RES_FILE_SIZE_LO = root_ip->i_size; fs_m_out.RES_UID = root_ip->i_uid; fs_m_out.RES_GID = root_ip->i_gid; fs_m_out.RES_CONREQS = 1; /* We can handle only 1 request at a time */ return(r); }
/*===========================================================================* * fs_utime * *===========================================================================*/ int fs_utime() { register struct inode *rip; register int r; /* Temporarily open the file. */ if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); /* * Only the owner of a file or the super_user can change the timestamps. * Here we assume VFS did that check before. */ r = OK; if(read_only(rip) != OK) r = EROFS; /* not even su can touch if R/O */ if(r == OK) { rip->i_update = CTIME; /* discard any stale ATIME and MTIME flags */ switch(fs_m_in.REQ_ACNSEC) { case UTIME_NOW: rip->i_update |= ATIME; break; case UTIME_OMIT: /* do not touch */ break; default: /* * cases fs_m_in.REQ_ACNSEC < 0 || fs_m_in.REQ_ACNSEC >= 1E9 * are caught by VFS to cooperate with old instances of EXT2 */ rip->i_atime = fs_m_in.REQ_ACTIME; /* * Ext2FS does not support better than second resolution, * so we discard REQ_ACNSEC to round down */ break; } switch(fs_m_in.REQ_MODNSEC) { case UTIME_NOW: rip->i_update |= MTIME; break; case UTIME_OMIT: /* do not touch */ break; default: /* * cases fs_m_in.REQ_MODNSEC < 0 || fs_m_in.REQ_MODNSEC >= 1E9 * are caught by VFS to cooperate with old instances of EXT2 */ rip->i_mtime = fs_m_in.REQ_MODTIME; /* * Ext2FS does not support better than second resolution, * so we discard REQ_MODNSEC to round down */ break; } rip->i_dirt = IN_DIRTY; } put_inode(rip); return(r); }
/*===========================================================================* * fs_mkdir * *===========================================================================*/ int fs_mkdir() { int r1, r2; /* status codes */ ino_t dot, dotdot; /* inode numbers for . and .. */ struct inode *rip, *ldirp; char lastc[NAME_MAX + 1]; /* last component */ phys_bytes len; /* Copy the last component and set up caller's user and group id */ len = fs_m_in.REQ_PATH_LEN; /* including trailing '\0' */ if (len > NAME_MAX + 1 || len > EXT2_NAME_MAX + 1) return(ENAMETOOLONG); err_code = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT, (vir_bytes) 0, (vir_bytes) lastc, (phys_bytes) len); if(err_code != OK) return(err_code); NUL(lastc, len, sizeof(lastc)); caller_uid = (uid_t) fs_m_in.REQ_UID; caller_gid = (gid_t) fs_m_in.REQ_GID; /* Get last directory inode */ if((ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(ENOENT); /* Next make the inode. If that fails, return error code. */ rip = new_node(ldirp, lastc, (ino_t) fs_m_in.REQ_MODE, (block_t) 0); if(rip == NULL || err_code == EEXIST) { put_inode(rip); /* can't make dir: it already exists */ put_inode(ldirp); return(err_code); } /* Get the inode numbers for . and .. to enter in the directory. */ dotdot = ldirp->i_num; /* parent's inode number */ dot = rip->i_num; /* inode number of the new dir itself */ /* Now make dir entries for . and .. unless the disk is completely full. */ /* Use dot1 and dot2, so the mode of the directory isn't important. */ rip->i_mode = (mode_t) fs_m_in.REQ_MODE; /* set mode */ /* enter . in the new dir*/ r1 = search_dir(rip, dot1, &dot, ENTER, IGN_PERM, I_DIRECTORY); /* enter .. in the new dir */ r2 = search_dir(rip, dot2, &dotdot, ENTER, IGN_PERM, I_DIRECTORY); /* If both . and .. were successfully entered, increment the link counts. */ if (r1 == OK && r2 == OK) { /* Normal case. It was possible to enter . and .. in the new dir. */ rip->i_links_count++; /* this accounts for . */ ldirp->i_links_count++; /* this accounts for .. */ ldirp->i_dirt = IN_DIRTY; /* mark parent's inode as dirty */ } else { /* It was not possible to enter . or .. probably disk was full - * links counts haven't been touched. */ if (search_dir(ldirp, lastc, NULL, DELETE, IGN_PERM, 0) != OK) panic("Dir disappeared: %d ", rip->i_num); rip->i_links_count--; /* undo the increment done in new_node() */ } rip->i_dirt = IN_DIRTY; /* either way, i_links_count has changed */ put_inode(ldirp); /* return the inode of the parent dir */ put_inode(rip); /* return the inode of the newly made dir */ return(err_code); /* new_node() always sets 'err_code' */ }
/*===========================================================================* * do_getdents * *===========================================================================*/ PUBLIC int do_getdents() { /* Retrieve directory entries. */ char name[NAME_MAX+1]; struct inode *ino, *child; struct dirent *dent; struct hgfs_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 = HGFS_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 HGFS 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 = hgfs_readdir(ino->i_dir, pos - 2, name, sizeof(name), &attr); if (r != OK || !name[0]) { /* No more entries? Then close the handle and stop. */ /* VMware Player 3 returns an empty name, instead of * EINVAL, when reading from an EOF position right * after opening the directory handle. Seems to be a * newly introduced bug.. */ if (r == EINVAL || !name[0]) { 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 mkfs(struct filesys *fs, dev_t dev) { struct superblock *sb; struct block_device *bdev; int i, bcount; if(!(bdev = blk_open(dev))) { return -1; } fs->bdev = bdev; if(!(sb = malloc(BLKSZ))) { blk_close(bdev); return -1; } fs->sb = sb; /* populate the superblock */ sb->magic = MAGIC; sb->ver = FS_VER; sb->blksize = BLKSZ; sb->num_blocks = bdev->size; sb->num_inodes = sb->num_blocks / 4; /* inode bitmap just after the superblock */ sb->ibm_start = 2; sb->ibm_count = (sb->num_inodes + BLKBITS - 1) / BLKBITS; /* also allocate and initialize in-memory inode bitmap */ sb->ibm = malloc(sb->ibm_count * BLKSZ); assert(sb->ibm); memset(sb->ibm, 0, sb->ibm_count * BLKSZ); /* XXX mark inode 0 as used always */ BM_SET(sb->ibm, 0); /* block bitmap just after the inode bitmap */ sb->bm_start = sb->ibm_start + sb->ibm_count; sb->bm_count = (sb->num_blocks + BLKBITS - 1) / BLKBITS; /* also allocate and initialize in-memory block bitmap */ sb->bm = malloc(sb->bm_count * BLKSZ); assert(sb->bm); memset(sb->bm, 0, sb->bm_count * BLKSZ); /* inode table, just after the block bitmap */ sb->itbl_start = sb->bm_start + sb->bm_count; sb->itbl_count = (sb->num_inodes * sizeof(struct inode) + BLKSZ - 1) / BLKSZ; /* mark all used blocks as used */ bcount = sb->itbl_start + sb->itbl_count; memset(sb->bm, 0xff, bcount / 8); for(i=0; i<bcount % 8; i++) { int bit = bcount / 8 + i; BM_SET(sb->bm, bit); } /* create the root directory */ sb->root = newdir(fs, 0); sb->root_ino = sb->root->ino; /* and write the inode to disk */ put_inode(fs, sb->root); return 0; }
int searchdir(const char *name) { struct inode *inode = NULL; struct inode *parent = NULL; struct file *file; char *pathbuf = NULL; char *part, *p, echar; int symlink_count = MAX_SYMLINK_CNT; dprintf("searchdir: %s root: %p cwd: %p\n", name, this_fs->root, this_fs->cwd); if (!(file = alloc_file())) goto err_no_close; file->fs = this_fs; /* if we have ->searchdir method, call it */ if (file->fs->fs_ops->searchdir) { file->fs->fs_ops->searchdir(name, file); if (file->inode) return file_to_handle(file); else goto err; } /* else, try the generic-path-lookup method */ parent = get_inode(this_fs->cwd); p = pathbuf = strdup(name); if (!pathbuf) goto err; do { got_link: if (*p == '/') { put_inode(parent); parent = get_inode(this_fs->root); } do { inode = get_inode(parent); while (*p == '/') p++; if (!*p) break; part = p; while ((echar = *p) && echar != '/') p++; *p++ = '\0'; if (part[0] == '.' && part[1] == '.' && part[2] == '\0') { if (inode->parent) { put_inode(parent); parent = get_inode(inode->parent); put_inode(inode); inode = NULL; if (!echar) { /* Terminal double dots */ inode = parent; parent = inode->parent ? get_inode(inode->parent) : NULL; } } } else if (part[0] != '.' || part[1] != '\0') { inode = this_fs->fs_ops->iget(part, parent); if (!inode) goto err; if (inode->mode == DT_LNK) { char *linkbuf, *q; int name_len = echar ? strlen(p) : 0; int total_len = inode->size + name_len + 2; int link_len; if (!this_fs->fs_ops->readlink || --symlink_count == 0 || /* limit check */ total_len > MAX_SYMLINK_BUF) goto err; linkbuf = malloc(total_len); if (!linkbuf) goto err; link_len = this_fs->fs_ops->readlink(inode, linkbuf); if (link_len <= 0) { free(linkbuf); goto err; } q = linkbuf + link_len; if (echar) { if (link_len > 0 && q[-1] != '/') *q++ = '/'; memcpy(q, p, name_len+1); } else { *q = '\0'; } free(pathbuf); p = pathbuf = linkbuf; put_inode(inode); inode = NULL; goto got_link; } inode->name = strdup(part); dprintf("path component: %s\n", inode->name); inode->parent = parent; parent = NULL; if (!echar) break; if (inode->mode != DT_DIR) goto err; parent = inode; inode = NULL; } } while (echar); } while (0); free(pathbuf); pathbuf = NULL; put_inode(parent); parent = NULL; if (!inode) goto err; file->inode = inode; file->offset = 0; return file_to_handle(file); err: put_inode(inode); put_inode(parent); if (pathbuf) free(pathbuf); _close_file(file); err_no_close: return -1; }
/*===========================================================================* * fs_link * *===========================================================================*/ int fs_link() { /* Perform the link(name1, name2) system call. */ struct inode *ip, *rip; register int r; char string[MFS_NAME_MAX]; struct inode *new_ip; phys_bytes len; len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(string)); /* Copy the link name's last component */ r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT, (vir_bytes) 0, (vir_bytes) string, (size_t) len); if (r != OK) return r; NUL(string, len, sizeof(string)); /* Temporarily open the file. */ if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); /* Check to see if the file has maximum number of links already. */ r = OK; if(rip->i_nlinks >= LINK_MAX) r = EMLINK; /* Only super_user may link to directories. */ if(r == OK) if( (rip->i_mode & I_TYPE) == I_DIRECTORY && caller_uid != SU_UID) r = EPERM; /* If error with 'name', return the inode. */ if (r != OK) { put_inode(rip); return(r); } /* Temporarily open the last dir */ if( (ip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_DIR_INO)) == NULL) { put_inode(rip); return(EINVAL); } if (ip->i_nlinks == NO_LINK) { /* Dir does not actually exist */ put_inode(rip); put_inode(ip); return(ENOENT); } /* If 'name2' exists in full (even if no space) set 'r' to error. */ if((new_ip = advance(ip, string, IGN_PERM)) == NULL) { r = err_code; if(r == ENOENT) r = OK; } else { put_inode(new_ip); r = EEXIST; } /* Try to link. */ if(r == OK) r = search_dir(ip, string, &rip->i_num, ENTER, IGN_PERM); /* If success, register the linking. */ if(r == OK) { rip->i_nlinks++; rip->i_update |= CTIME; IN_MARKDIRTY(rip); } /* Done. Release both inodes. */ put_inode(rip); put_inode(ip); return(r); }
static int file_block(struct filesys *fs, struct inode *node, int boffs, int allocate) { int res, idx, node_dirty = 0; blkid *barr; /* out of bounds */ if(boffs < 0 || boffs >= MAX_DIND) { return 0; } /* is it a direct block ? */ if(boffs < NDIRBLK) { if(!(res = node->blk[boffs]) && allocate) { res = node->blk[boffs] = alloc_block(fs); if(res) { zero_block(fs, res); /* also write back the modified inode */ put_inode(fs, node); } } return res; } barr = malloc(fs->sb->blksize); assert(barr); /* is it an indirect block ? */ if(boffs < MAX_IND) { int ind_dirty = 0; if(node->ind) { /* read the indirect block */ blk_read(fs->bdev, node->ind, 1, barr); } else { /* does not exist... try to allocate if requested */ if(!allocate || !(node->ind = alloc_block(fs))) { res = 0; goto end; } /* allocated a block clear the buffer, and invalidate everything */ memset(barr, 0, sizeof fs->sb->blksize); node_dirty = 1; ind_dirty = 1; } idx = boffs - NDIRBLK; if(!(res = barr[idx])) { if(allocate && (res = barr[idx] = alloc_block(fs))) { ind_dirty = 1; } } /* write back the indirect block if needed */ if(ind_dirty) { blk_write(fs->bdev, node->ind, 1, barr); } goto end; } /* TODO check/rewrite this */ #if 0 /* is it a double-indirect block ? */ if(boffs < MAX_DIND) { /* first read the dind block and find the index of the ind block */ if(!node->dind) { if(allocate) { /* allocate and zero-out the double indirect block */ res = node->dind = alloc_block(fs); if(res) { zero_block(fs, res); } } else { res = 0; goto end; } } blk_read(fd->bdev, node->dind, 1, barr); idx = (boffs - MAX_IND) / BLK_BLKID; /* then read the ind block and find the index of the block */ if(!barr[idx]) { res = 0; goto end; } blk_read(fd->bdev, barr[idx], 1, barr); res = barr[(boffs - MAX_IND) % BLK_BLKID]; } #endif end: if(node_dirty) { put_inode(fs, node); } free(barr); return res; }
/** * Remove a file. * * @note We clear the i-node in inode_array[] although it is not really needed. * We don't clear the data bytes so the file is recoverable. * * @return On success, zero is returned. On error, -1 is returned. *****************************************************************************/ PUBLIC int do_unlink() { char pathname[MAX_PATH]; /* get parameters from the message */ int name_len = fs_msg.NAME_LEN; /* length of filename */ int src = fs_msg.source; /* caller proc nr. */ assert(name_len < MAX_PATH); phys_copy((void*)va2la(TASK_FS, pathname), (void*)va2la(src, fs_msg.PATHNAME), name_len); pathname[name_len] = 0; if (strcmp(pathname , "/") == 0) { printl("FS:do_unlink():: cannot unlink the root\n"); return -1; } int inode_nr = search_file(pathname); if (inode_nr == INVALID_INODE) { /* file not found */ printl("FS::do_unlink():: search_file() returns " "invalid inode: %s\n", pathname); return -1; } char filename[MAX_PATH]; struct inode * dir_inode; if (strip_path(filename, pathname, &dir_inode) != 0) return -1; struct inode * pin = get_inode(dir_inode->i_dev, inode_nr); if (pin->i_mode != I_REGULAR) { /* can only remove regular files */ printl("cannot remove file %s, because " "it is not a regular file.\n", pathname); return -1; } if (pin->i_cnt > 1) { /* the file was opened */ printl("cannot remove file %s, because pin->i_cnt is %d.\n", pathname, pin->i_cnt); return -1; } struct super_block * sb = get_super_block(pin->i_dev); /*************************/ /* free the bit in i-map */ /*************************/ int byte_idx = inode_nr / 8; int bit_idx = inode_nr % 8; assert(byte_idx < SECTOR_SIZE); /* we have only one i-map sector */ /* read sector 2 (skip bootsect and superblk): */ RD_SECT(pin->i_dev, 2); assert(fsbuf[byte_idx % SECTOR_SIZE] & (1 << bit_idx)); fsbuf[byte_idx % SECTOR_SIZE] &= ~(1 << bit_idx); WR_SECT(pin->i_dev, 2); /**************************/ /* free the bits in s-map */ /**************************/ /* * bit_idx: bit idx in the entire i-map * ... ____|____ * \ .-- byte_cnt: how many bytes between * \ | the first and last byte * +-+-+-+-+-+-+-+-+ V +-+-+-+-+-+-+-+-+ * ... | | | | | |*|*|*|...|*|*|*|*| | | | | * +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 * ...__/ * byte_idx: byte idx in the entire i-map */ bit_idx = pin->i_start_sect - sb->n_1st_sect + 1; byte_idx = bit_idx / 8; int bits_left = pin->i_nr_sects; int byte_cnt = (bits_left - (8 - (bit_idx % 8))) / 8; /* current sector nr. */ int s = 2 /* 2: bootsect + superblk */ + sb->nr_imap_sects + byte_idx / SECTOR_SIZE; RD_SECT(pin->i_dev, s); int i; /* clear the first byte */ for (i = bit_idx % 8; (i < 8) && bits_left; i++,bits_left--) { //assert((fsbuf[byte_idx % SECTOR_SIZE] >> i & 1) == 1); fsbuf[byte_idx % SECTOR_SIZE] &= ~(1 << i); } /* clear bytes from the second byte to the second to last */ int k; i = (byte_idx % SECTOR_SIZE) + 1; /* the second byte */ for (k = 0; k < byte_cnt; k++,i++,bits_left-=8) { if (i == SECTOR_SIZE) { i = 0; WR_SECT(pin->i_dev, s); RD_SECT(pin->i_dev, ++s); } //assert(fsbuf[i] == 0xFF); fsbuf[i] = 0; } /* clear the last byte */ if (i == SECTOR_SIZE) { i = 0; WR_SECT(pin->i_dev, s); RD_SECT(pin->i_dev, ++s); } unsigned char mask = ~((unsigned char)(~0) << bits_left); //assert((fsbuf[i] & mask) == mask); fsbuf[i] &= (~0) << bits_left; WR_SECT(pin->i_dev, s); /***************************/ /* clear the i-node itself */ /***************************/ pin->i_mode = 0; pin->i_size = 0; pin->i_start_sect = 0; pin->i_nr_sects = 0; sync_inode(pin); /* release slot in inode_table[] */ put_inode(pin); /************************************************/ /* set the inode-nr to 0 in the directory entry */ /************************************************/ int dir_blk0_nr = dir_inode->i_start_sect; int nr_dir_blks = (dir_inode->i_size + SECTOR_SIZE) / SECTOR_SIZE; int nr_dir_entries = dir_inode->i_size / DIR_ENTRY_SIZE; /* including unused slots * (the file has been * deleted but the slot * is still there) */ int m = 0; struct dir_entry * pde = 0; int flg = 0; int dir_size = 0; for (i = 0; i < nr_dir_blks; i++) { RD_SECT(dir_inode->i_dev, dir_blk0_nr + i); pde = (struct dir_entry *)fsbuf; int j; for (j = 0; j < SECTOR_SIZE / DIR_ENTRY_SIZE; j++,pde++) { if (++m > nr_dir_entries) break; if (pde->inode_nr == inode_nr) { /* pde->inode_nr = 0; */ memset(pde, 0, DIR_ENTRY_SIZE); WR_SECT(dir_inode->i_dev, dir_blk0_nr + i); flg = 1; break; } if (pde->inode_nr != INVALID_INODE) dir_size += DIR_ENTRY_SIZE; } if (m > nr_dir_entries || /* all entries have been iterated OR */ flg) /* file is found */ break; } assert(flg); if (m == nr_dir_entries) { /* the file is the last one in the dir */ dir_inode->i_size = dir_size; sync_inode(dir_inode); } return 0; }
/*===========================================================================* * fs_link * *===========================================================================*/ int fs_link(ino_t dir_nr, char *name, ino_t ino_nr) { /* Perform the link(name1, name2) system call. */ struct inode *ip, *rip; register int r; struct inode *new_ip; /* Temporarily open the file. */ if( (rip = get_inode(fs_dev, ino_nr)) == NULL) return(EINVAL); /* Check to see if the file has maximum number of links already. */ r = OK; if (rip->i_links_count >= USHRT_MAX) r = EMLINK; if(rip->i_links_count >= LINK_MAX) r = EMLINK; /* Linking to directories is too dangerous to allow. */ if(r == OK) if( (rip->i_mode & I_TYPE) == I_DIRECTORY) r = EPERM; /* If error with 'name', return the inode. */ if (r != OK) { put_inode(rip); return(r); } /* Temporarily open the last dir */ if( (ip = get_inode(fs_dev, dir_nr)) == NULL) { put_inode(rip); return(EINVAL); } if (ip->i_links_count == NO_LINK) { /* Dir does not actually exist */ put_inode(rip); put_inode(ip); return(ENOENT); } /* If 'name2' exists in full (even if no space) set 'r' to error. */ if ((new_ip = advance(ip, name)) == NULL) { r = err_code; if(r == ENOENT) r = OK; } else { put_inode(new_ip); r = EEXIST; } /* Try to link. */ if(r == OK) r = search_dir(ip, name, &rip->i_num, ENTER, rip->i_mode & I_TYPE); /* If success, register the linking. */ if(r == OK) { rip->i_links_count++; rip->i_update |= CTIME; rip->i_dirt = IN_DIRTY; } /* Done. Release both inodes. */ put_inode(rip); put_inode(ip); return(r); }
void dir_test(){ struct inode* root_inode; struct inode *rip; char string[DIRSIZ]; int number; int * inode_num = & number; int r; root_inode = get_inode(1); if(root_inode == NIL_INODE){ printf("root_inode is a null inode\n"); return; } /* printf("root_inode size is %d\n", root_inode->i_size); */ /* delete_dir(root_inode, 0); */ /* empty_inode_space(root_inode); */ /* put_inode(root_inode); */ /* return; */ /* my_strcpy(string, "usr"); */ /* if( r = search_dir(root_inode, string, inode_num, LOOK_UP) != OK){ */ /* printf("LOOK_UP a usr error: %s\n", strerror(r)); */ /* put_inode(root_inode); */ /* return; */ /* } */ /* printf("this time i node size is %d\n", root_inode->i_size); */ /* put_inode(root_inode); */ /* return; */ my_strcpy(string, ".."); *inode_num = root_inode->i_num; if (r = search_dir(root_inode, string, inode_num, ENTER) != OK){ printf("enter a item error: %s\n", strerror(r)); put_inode(root_inode); return; } my_strcpy(string, "."); *inode_num = root_inode->i_num; if (r = search_dir(root_inode, string, inode_num, ENTER) != OK){ printf("enter a item error: %s\n", strerror(r)); put_inode(root_inode); return; } root_inode->i_dirt = DIRTY; put_inode(root_inode); show_file_list(); /* return; */ printf("\n"); my_strcpy(string, "."); root_inode = get_inode(1); *inode_num = 0; if (r = search_dir(root_inode, string, inode_num, LOOK_UP) != OK){ printf("find a item error: %s\n", strerror(r)); put_inode(root_inode); return; } if(*inode_num != root_inode->i_num){ printf("can't find . in the root directory!!!\n"); put_inode(root_inode); return; } put_inode(root_inode); my_mkdir("./usr"); my_mkdir("src"); my_mkdir("../root"); show_file_list(); printf("\n"); root_inode = last_dir("./../usr", string); if(root_inode == NIL_INODE){ printf("last_dir error: can't find root dir\n"); return; } if(root_inode->i_num != 1){ printf("this time last dir is not root_inode, it's i_num is %d\n", root_inode->i_num); put_inode(root_inode); return; } printf("string remain is %s\n", string); show_file_list(); printf("\n"); rip = advance(root_inode, string); if(rip == NIL_INODE){ printf("advance error: can't find usr dir\n"); return; } show_file_list(); printf("\n"); put_inode(rip); put_inode(root_inode); if(my_rmdir("/src") != OK){ printf("can't remove dir src\n"); return; } show_file_list(); }
/*===========================================================================* * do_slink * *===========================================================================*/ PUBLIC int do_slink() { /* Perform the symlink(name1, name2) system call. */ register int r; /* error code */ char string[NAME_MAX]; /* last component of the new dir's path name */ struct inode *sip; /* inode containing symbolic link */ struct buf *bp; /* disk buffer for link */ struct inode *ldirp; /* directory containing link */ if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) return(err_code); if (m_in.name1_length <= 1 || m_in.name1_length >= _MIN_BLOCK_SIZE) return(ENAMETOOLONG); /* Create the inode for the symlink. */ sip = new_node(&ldirp, user_path, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES), (zone_t) 0, TRUE, string); /* Allocate a disk block for the contents of the symlink. * Copy contents of symlink (the name pointed to) into first disk block. */ if ((r = err_code) == OK) { r = (bp = new_block(sip, (off_t) 0)) == NIL_BUF ? err_code : sys_vircopy(who_e, D, (vir_bytes) m_in.name1, SELF, D, (vir_bytes) bp->b_data, (vir_bytes) m_in.name1_length-1); if(r == OK) { bp->b_data[_MIN_BLOCK_SIZE-1] = '\0'; sip->i_size = strlen(bp->b_data); if(sip->i_size != m_in.name1_length-1) { /* This can happen if the user provides a buffer * with a \0 in it. This can cause a lot of trouble * when the symlink is used later. We could just use * the strlen() value, but we want to let the user * know he did something wrong. ENAMETOOLONG doesn't * exactly describe the error, but there is no * ENAMETOOWRONG. */ r = ENAMETOOLONG; } } put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NIL_BUF. */ if (r != OK) { sip->i_nlinks = 0; if (search_dir(ldirp, string, (ino_t *) 0, DELETE) != OK) panic(__FILE__, "Symbolic link vanished", NO_NUM); } } /* put_inode() accepts NIL_INODE as a noop, so the below are safe. */ put_inode(sip); put_inode(ldirp); return(r); }
/*===========================================================================* * fs_slink * *===========================================================================*/ PUBLIC int fs_slink() { phys_bytes len; struct inode *sip; /* inode containing symbolic link */ struct inode *ldirp; /* directory containing link */ register int r; /* error code */ char string[MFS_NAME_MAX]; /* last component of the new dir's path name */ struct buf *bp; /* disk buffer for link */ caller_uid = (uid_t) fs_m_in.REQ_UID; caller_gid = (gid_t) fs_m_in.REQ_GID; /* Copy the link name's last component */ len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(string)); r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT, (vir_bytes) 0, (vir_bytes) string, (size_t) len, D); if (r != OK) return(r); NUL(string, len, sizeof(string)); /* Temporarily open the dir. */ if( (ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); /* Create the inode for the symlink. */ sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES), (zone_t) 0); /* Allocate a disk block for the contents of the symlink. * Copy contents of symlink (the name pointed to) into first disk block. */ if( (r = err_code) == OK) { bp = new_block(sip, (off_t) 0); if (bp == NULL) r = err_code; else r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT3, (vir_bytes) 0, (vir_bytes) bp->b_data, (size_t) fs_m_in.REQ_MEM_SIZE, D); if(bp != NULL && r == OK) { bp->b_data[_MIN_BLOCK_SIZE-1] = '\0'; sip->i_size = (off_t) strlen(bp->b_data); if(sip->i_size != fs_m_in.REQ_MEM_SIZE) { /* This can happen if the user provides a buffer * with a \0 in it. This can cause a lot of trouble * when the symlink is used later. We could just use * the strlen() value, but we want to let the user * know he did something wrong. ENAMETOOLONG doesn't * exactly describe the error, but there is no * ENAMETOOWRONG. */ r = ENAMETOOLONG; } } put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NULL. */ if(r != OK) { sip->i_nlinks = NO_LINK; if(search_dir(ldirp, string, NULL, DELETE, IGN_PERM) != OK) panic("Symbolic link vanished"); } } /* put_inode() accepts NULL as a noop, so the below are safe. */ put_inode(sip); put_inode(ldirp); return(r); }
/*===========================================================================* * common_open * *===========================================================================*/ PRIVATE int common_open(register int oflags, mode_t omode) { /* Common code from do_creat and do_open. */ struct inode *rip, *ldirp; int r, b, exist = TRUE; dev_t dev; mode_t bits; off_t pos; struct filp *fil_ptr, *filp2; /* Remap the bottom two bits of oflags. */ bits = (mode_t) mode_map[oflags & O_ACCMODE]; /* See if file descriptor and filp slots are available. */ if ( (r = get_fd(0, bits, &m_in.fd, &fil_ptr)) != OK) return(r); /* If O_CREATE is set, try to make the file. */ if (oflags & O_CREAT) { /* Create a new inode by calling new_node(). */ omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask); rip = new_node(&ldirp, user_path, omode, NO_ZONE, oflags&O_EXCL, NULL); r = err_code; put_inode(ldirp); if (r == OK) exist = FALSE; /* we just created the file */ else if (r != EEXIST) return(r); /* other error */ else exist = !(oflags & O_EXCL); /* file exists, if the O_EXCL flag is set this is an error */ } else { /* Scan path name. */ if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code); } /* Claim the file descriptor and filp slot and fill them in. */ fp->fp_filp[m_in.fd] = fil_ptr; FD_SET(m_in.fd, &fp->fp_filp_inuse); fil_ptr->filp_count = 1; fil_ptr->filp_ino = rip; fil_ptr->filp_flags = oflags; /* Only do the normal open code if we didn't just create the file. */ if (exist) { /* Check protections. */ if ((r = forbidden(rip, bits)) == OK) { /* Opening reg. files directories and special files differ. */ switch (rip->i_mode & I_TYPE) { case I_REGULAR: /* Truncate regular file if O_TRUNC. */ if (oflags & O_TRUNC) { if ((r = forbidden(rip, W_BIT)) !=OK) break; truncate_inode(rip, 0); wipe_inode(rip); /* Send the inode from the inode cache to the * block cache, so it gets written on the next * cache flush. */ rw_inode(rip, WRITING); } break; case I_DIRECTORY: /* Directories may be read but not written. */ r = (bits & W_BIT ? EISDIR : OK); break; case I_CHAR_SPECIAL: case I_BLOCK_SPECIAL: /* Invoke the driver for special processing. */ dev = (dev_t) rip->i_zone[0]; r = dev_open(dev, who_e, bits | (oflags & ~O_ACCMODE)); break; case I_NAMED_PIPE: oflags |= O_APPEND; /* force append mode */ fil_ptr->filp_flags = oflags; r = pipe_open(rip, bits, oflags); if (r != ENXIO) { /* See if someone else is doing a rd or wt on * the FIFO. If so, use its filp entry so the * file position will be automatically shared. */ b = (bits & R_BIT ? R_BIT : W_BIT); fil_ptr->filp_count = 0; /* don't find self */ if ((filp2 = find_filp(rip, b)) != NIL_FILP) { /* Co-reader or writer found. Use it.*/ fp->fp_filp[m_in.fd] = filp2; filp2->filp_count++; filp2->filp_ino = rip; filp2->filp_flags = oflags; /* i_count was incremented incorrectly * by eatpath above, not knowing that * we were going to use an existing * filp entry. Correct this error. */ rip->i_count--; } else { /* Nobody else found. Restore filp. */ fil_ptr->filp_count = 1; if (b == R_BIT) pos = rip->i_zone[V2_NR_DZONES+0]; else pos = rip->i_zone[V2_NR_DZONES+1]; fil_ptr->filp_pos = pos; } } break; } } } /* If error, release inode. */ if (r != OK) { if (r == SUSPEND) return(r); /* Oops, just suspended */ fp->fp_filp[m_in.fd] = NIL_FILP; FD_CLR(m_in.fd, &fp->fp_filp_inuse); fil_ptr->filp_count= 0; put_inode(rip); return(r); } return(m_in.fd); }
/*===========================================================================* * new_node * *===========================================================================*/ PRIVATE struct inode *new_node(struct inode *ldirp, char *string, mode_t bits, zone_t z0) { /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir(). * In all cases it allocates a new inode, makes a directory entry for it in * the ldirp directory with string name, and initializes it. * It returns a pointer to the inode if it can do this; * otherwise it returns NULL. It always sets 'err_code' * to an appropriate value (OK or an error code). * * The parsed path rest is returned in 'parsed' if parsed is nonzero. It * has to hold at least MFS_NAME_MAX bytes. */ register struct inode *rip; register int r; if (ldirp->i_nlinks == NO_LINK) { /* Dir does not actually exist */ err_code = ENOENT; return(NULL); } /* Get final component of the path. */ rip = advance(ldirp, string, IGN_PERM); if (S_ISDIR(bits) && (ldirp->i_nlinks >= LINK_MAX)) { /* New entry is a directory, alas we can't give it a ".." */ put_inode(rip); err_code = EMLINK; return(NULL); } if ( rip == NULL && err_code == ENOENT) { /* Last path component does not exist. Make new directory entry. */ if ( (rip = alloc_inode((ldirp)->i_dev, bits)) == NULL) { /* Can't creat new inode: out of inodes. */ return(NULL); } /* Force inode to the disk before making directory entry to make * the system more robust in the face of a crash: an inode with * no directory entry is much better than the opposite. */ rip->i_nlinks++; rip->i_zone[0] = z0; /* major/minor device numbers */ rw_inode(rip, WRITING); /* force inode to disk now */ /* New inode acquired. Try to make directory entry. */ if((r=search_dir(ldirp, string, &rip->i_num, ENTER, IGN_PERM)) != OK) { rip->i_nlinks--; /* pity, have to free disk inode */ rip->i_dirt = DIRTY; /* dirty inodes are written out */ put_inode(rip); /* this call frees the inode */ err_code = r; return(NULL); } } else if (err_code == EENTERMOUNT || err_code == ELEAVEMOUNT) { r = EEXIST; } else { /* Either last component exists, or there is some problem. */ if (rip != NULL) r = EEXIST; else r = err_code; } /* The caller has to return the directory inode (*ldirp). */ err_code = r; return(rip); }
/*===========================================================================* * 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 restore_state() { FILE *fp; int i; struct hnode t_hnode; /* Temporary hash nodes */ struct unode t_unode; struct rnode t_rnode; struct anode t_anode; struct snode t_snode; struct inode t_inode; char buffer[BUFSIZE]; char tmp_buf[BUFSIZE]; u_long ul_bogus=0; fp=fopen(state_fname,"r"); if (fp==NULL) { /* Previous run data not found... */ if (verbose>1) printf("%s\n",msg_no_data); return 0; /* return with ok code */ } /* Reading previous run data... */ if (verbose>1) printf("%s %s\n",msg_get_data,state_fname); /* get easy stuff */ sprintf(tmp_buf,"# Webalizer V%s ",version); if ((fgets(buffer,BUFSIZE,fp)) != NULL) /* Header record */ {if (strncmp(buffer,tmp_buf,17)) return 99;} /* bad magic? */ else return 1; /* error exit */ /* Get current timestamp */ if ((fgets(buffer,BUFSIZE,fp)) != NULL) { sscanf(buffer,"%d %d %d %d %d %d", &cur_year, &cur_month, &cur_day, &cur_hour, &cur_min, &cur_sec); } else return 2; /* error exit */ /* calculate current timestamp (seconds since epoch) */ cur_tstamp=((jdate(cur_day,cur_month,cur_year)-epoch)*86400)+ (cur_hour*3600)+(cur_min*60)+cur_sec; /* Get monthly totals */ if ((fgets(buffer,BUFSIZE,fp)) != NULL) { sscanf(buffer,"%lu %lu %lu %lu %lu %lu %lf %lu %lu %lu", &t_hit, &t_file, &t_site, &t_url, &t_ref, &t_agent, &t_xfer, &t_page, &t_visit, &t_user); } else return 3; /* error exit */ /* Get daily totals */ if ((fgets(buffer,BUFSIZE,fp)) != NULL) { sscanf(buffer,"%lu %lu %lu %d %d", &dt_site, &ht_hit, &mh_hit, &f_day, &l_day); } else return 4; /* error exit */ /* get daily totals */ for (i=0;i<31;i++) { if ((fgets(buffer,BUFSIZE,fp)) != NULL) { sscanf(buffer,"%lu %lu %lf %lu %lu %lu", &tm_hit[i],&tm_file[i],&tm_xfer[i],&tm_site[i],&tm_page[i], &tm_visit[i]); } else return 5; /* error exit */ } /* get hourly totals */ for (i=0;i<24;i++) { if ((fgets(buffer,BUFSIZE,fp)) != NULL) { sscanf(buffer,"%lu %lu %lf %lu", &th_hit[i],&th_file[i],&th_xfer[i],&th_page[i]); } else return 6; /* error exit */ } /* get response code totals */ for (i=0;i<TOTAL_RC;i++) { if ((fgets(buffer,BUFSIZE,fp)) != NULL) sscanf(buffer,"%lu",&response[i].count); else return 7; /* error exit */ } /* Kludge for V2.01-06 TOTAL_RC off by one bug */ if (!strncmp(buffer,"# -urls- ",9)) response[TOTAL_RC-1].count=0; else { /* now do hash tables */ /* url table */ if ((fgets(buffer,BUFSIZE,fp)) != NULL) /* Table header */ { if (strncmp(buffer,"# -urls- ",9)) return 10; } /* (url) */ else return 10; /* error exit */ } while ((fgets(buffer,BUFSIZE,fp)) != NULL) { if (!strncmp(buffer,"# End Of Table ",15)) break; strncpy(tmp_buf,buffer,MAXURLH); tmp_buf[strlen(tmp_buf)-1]=0; if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 10; /* error exit */ if (!isdigit((int)buffer[0])) return 10; /* error exit */ /* load temporary node data */ sscanf(buffer,"%d %lu %lu %lf %lu %lu", &t_unode.flag,&t_unode.count, &t_unode.files, &t_unode.xfer, &t_unode.entry, &t_unode.exit); /* Good record, insert into hash table */ if (put_unode(tmp_buf,t_unode.flag,t_unode.count, t_unode.xfer,&ul_bogus,t_unode.entry,t_unode.exit,um_htab)) { if (verbose) /* Error adding URL node, skipping ... */ fprintf(stderr,"%s %s\n", msg_nomem_u, t_unode.string); } } /* monthly sites table */ if ((fgets(buffer,BUFSIZE,fp)) != NULL) /* Table header */ { if (strncmp(buffer,"# -sites- ",10)) return 8; } /* (monthly) */ else return 8; /* error exit */ while ((fgets(buffer,BUFSIZE,fp)) != NULL) { /* Check for end of table */ if (!strncmp(buffer,"# End Of Table ",15)) break; strncpy(tmp_buf,buffer,MAXHOST); tmp_buf[strlen(buffer)-1]=0; if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 8; /* error exit */ if (!isdigit((int)buffer[0])) return 8; /* error exit */ /* load temporary node data */ sscanf(buffer,"%d %lu %lu %lf %lu %lu", &t_hnode.flag,&t_hnode.count, &t_hnode.files, &t_hnode.xfer, &t_hnode.visit, &t_hnode.tstamp); /* get last url */ if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 8; /* error exit */ if (buffer[0]=='-') t_hnode.lasturl=blank_str; else { buffer[strlen(buffer)-1]=0; t_hnode.lasturl=find_url(buffer); } /* Good record, insert into hash table */ if (put_hnode(tmp_buf,t_hnode.flag, t_hnode.count,t_hnode.files,t_hnode.xfer,&ul_bogus, t_hnode.visit+1,t_hnode.tstamp,t_hnode.lasturl,sm_htab)) { /* Error adding host node (monthly), skipping .... */ if (verbose) fprintf(stderr,"%s %s\n",msg_nomem_mh, t_hnode.string); } } /* Daily sites table */ if ((fgets(buffer,BUFSIZE,fp)) != NULL) /* Table header */ { if (strncmp(buffer,"# -sites- ",10)) return 9; } /* (daily) */ else return 9; /* error exit */ while ((fgets(buffer,BUFSIZE,fp)) != NULL) { /* Check for end of table */ if (!strncmp(buffer,"# End Of Table ",15)) break; strncpy(tmp_buf,buffer,MAXHOST); tmp_buf[strlen(buffer)-1]=0; if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 9; /* error exit */ if (!isdigit((int)buffer[0])) return 9; /* error exit */ /* load temporary node data */ sscanf(buffer,"%d %lu %lu %lf %lu %lu", &t_hnode.flag,&t_hnode.count, &t_hnode.files, &t_hnode.xfer, &t_hnode.visit, &t_hnode.tstamp); /* get last url */ if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 9; /* error exit */ if (buffer[0]=='-') t_hnode.lasturl=blank_str; else { buffer[strlen(buffer)-1]=0; t_hnode.lasturl=find_url(buffer); } /* Good record, insert into hash table */ if (put_hnode(tmp_buf,t_hnode.flag, t_hnode.count,t_hnode.files,t_hnode.xfer,&ul_bogus, t_hnode.visit+1,t_hnode.tstamp,t_hnode.lasturl,sd_htab)) { /* Error adding host node (daily), skipping .... */ if (verbose) fprintf(stderr,"%s %s\n",msg_nomem_dh, t_hnode.string); } } /* Referrers table */ if ((fgets(buffer,BUFSIZE,fp)) != NULL) /* Table header */ { if (strncmp(buffer,"# -referrers- ",14)) return 11; } /* (referrers)*/ else return 11; /* error exit */ while ((fgets(buffer,BUFSIZE,fp)) != NULL) { if (!strncmp(buffer,"# End Of Table ",15)) break; strncpy(tmp_buf,buffer,MAXREFH); tmp_buf[strlen(buffer)-1]=0; if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 11; /* error exit */ if (!isdigit((int)buffer[0])) return 11; /* error exit */ /* load temporary node data */ sscanf(buffer,"%d %lu",&t_rnode.flag,&t_rnode.count); /* insert node */ if (put_rnode(tmp_buf,t_rnode.flag, t_rnode.count, &ul_bogus, rm_htab)) { if (verbose) fprintf(stderr,"%s %s\n", msg_nomem_r, log_rec.refer); } } /* Agents table */ if ((fgets(buffer,BUFSIZE,fp)) != NULL) /* Table header */ { if (strncmp(buffer,"# -agents- ",11)) return 12; } /* (agents)*/ else return 12; /* error exit */ while ((fgets(buffer,BUFSIZE,fp)) != NULL) { if (!strncmp(buffer,"# End Of Table ",15)) break; strncpy(tmp_buf,buffer,MAXAGENT); tmp_buf[strlen(buffer)-1]=0; if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 12; /* error exit */ if (!isdigit((int)buffer[0])) return 12; /* error exit */ /* load temporary node data */ sscanf(buffer,"%d %lu",&t_anode.flag,&t_anode.count); /* insert node */ if (put_anode(tmp_buf,t_anode.flag,t_anode.count, &ul_bogus,am_htab)) { if (verbose) fprintf(stderr,"%s %s\n", msg_nomem_a, log_rec.agent); } } /* Search Strings table */ if ((fgets(buffer,BUFSIZE,fp)) != NULL) /* Table header */ { if (strncmp(buffer,"# -search string",16)) return 13; } /* (search)*/ else return 13; /* error exit */ while ((fgets(buffer,BUFSIZE,fp)) != NULL) { if (!strncmp(buffer,"# End Of Table ",15)) break; strncpy(tmp_buf,buffer,MAXSRCH); tmp_buf[strlen(buffer)-1]=0; if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 13; /* error exit */ if (!isdigit((int)buffer[0])) return 13; /* error exit */ /* load temporary node data */ sscanf(buffer,"%lu",&t_snode.count); /* insert node */ if (put_snode(tmp_buf,t_snode.count,sr_htab)) { if (verbose) fprintf(stderr,"%s %s\n", msg_nomem_sc, t_snode.string); } } /* usernames table */ if ((fgets(buffer,BUFSIZE,fp)) != NULL) /* Table header */ { if (strncmp(buffer,"# -usernames- ",10)) return 14; } else return 14; /* error exit */ while ((fgets(buffer,BUFSIZE,fp)) != NULL) { /* Check for end of table */ if (!strncmp(buffer,"# End Of Table ",15)) break; strncpy(tmp_buf,buffer,MAXIDENT); tmp_buf[strlen(buffer)-1]=0; if ((fgets(buffer,BUFSIZE,fp)) == NULL) return 14; /* error exit */ if (!isdigit((int)buffer[0])) return 14; /* error exit */ /* load temporary node data */ sscanf(buffer,"%d %lu %lu %lf %lu %lu", &t_inode.flag,&t_inode.count, &t_inode.files, &t_inode.xfer, &t_inode.visit, &t_inode.tstamp); /* Good record, insert into hash table */ if (put_inode(tmp_buf,t_inode.flag, t_inode.count,t_inode.files,t_inode.xfer,&ul_bogus, t_inode.visit+1,t_inode.tstamp,im_htab)) { if (verbose) /* Error adding username node, skipping .... */ fprintf(stderr,"%s %s\n",msg_nomem_i, t_inode.string); } } fclose(fp); check_dup = 1; /* enable duplicate checking */ return 0; /* return with ok code */ }
/*===========================================================================* * fs_slink * *===========================================================================*/ int fs_slink() { phys_bytes len; struct inode *sip; /* inode containing symbolic link */ struct inode *ldirp; /* directory containing link */ register int r; /* error code */ char string[NAME_MAX]; /* last component of the new dir's path name */ char* link_target_buf = NULL; /* either sip->i_block or bp->b_data */ struct buf *bp = NULL; /* disk buffer for link */ caller_uid = (uid_t) fs_m_in.REQ_UID; caller_gid = (gid_t) fs_m_in.REQ_GID; /* Copy the link name's last component */ len = fs_m_in.REQ_PATH_LEN; if (len > NAME_MAX || len > EXT2_NAME_MAX) return(ENAMETOOLONG); r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT, (vir_bytes) 0, (vir_bytes) string, (size_t) len); if (r != OK) return(r); NUL(string, len, sizeof(string)); /* Temporarily open the dir. */ if( (ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); /* Create the inode for the symlink. */ sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES), (block_t) 0); /* If we can then create fast symlink (store it in inode), * Otherwise allocate a disk block for the contents of the symlink and * copy contents of symlink (the name pointed to) into first disk block. */ if( (r = err_code) == OK) { if ( (fs_m_in.REQ_MEM_SIZE + 1) > sip->i_sp->s_block_size) { r = ENAMETOOLONG; } else if ((fs_m_in.REQ_MEM_SIZE + 1) <= MAX_FAST_SYMLINK_LENGTH) { r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT3, (vir_bytes) 0, (vir_bytes) sip->i_block, (vir_bytes) fs_m_in.REQ_MEM_SIZE); sip->i_dirt = IN_DIRTY; link_target_buf = (char*) sip->i_block; } else { if ((bp = new_block(sip, (off_t) 0)) != NULL) { sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT3, (vir_bytes) 0, (vir_bytes) b_data(bp), (vir_bytes) fs_m_in.REQ_MEM_SIZE); lmfs_markdirty(bp); link_target_buf = b_data(bp); } else { r = err_code; } } if (r == OK) { assert(link_target_buf); link_target_buf[fs_m_in.REQ_MEM_SIZE] = '\0'; sip->i_size = (off_t) strlen(link_target_buf); if (sip->i_size != fs_m_in.REQ_MEM_SIZE) { /* This can happen if the user provides a buffer * with a \0 in it. This can cause a lot of trouble * when the symlink is used later. We could just use * the strlen() value, but we want to let the user * know he did something wrong. ENAMETOOLONG doesn't * exactly describe the error, but there is no * ENAMETOOWRONG. */ r = ENAMETOOLONG; } } put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NULL. */ if(r != OK) { sip->i_links_count = NO_LINK; if (search_dir(ldirp, string, NULL, DELETE, IGN_PERM, 0) != OK) panic("Symbolic link vanished"); } } /* put_inode() accepts NULL as a noop, so the below are safe. */ put_inode(sip); put_inode(ldirp); return(r); }
/*===========================================================================* * fs_readsuper_s * *===========================================================================*/ PUBLIC int fs_readsuper_s() { /* This function reads the superblock of the partition, gets the root inode * and sends back the details of them. Note, that the FS process does not * know the index of the vmnt object which refers to it, whenever the pathname * lookup leaves a partition an ELEAVEMOUNT error is transferred back * so that the VFS knows that it has to find the vnode on which this FS * process' partition is mounted on. */ struct super_block *xp; struct inode *root_ip; cp_grant_id_t label_gid; size_t label_len; int r = OK; unsigned long tasknr; endpoint_t driver_e; fs_dev = fs_m_in.REQ_DEV; label_gid= fs_m_in.REQ_GRANT2; label_len= fs_m_in.REQ_PATH_LEN; if (label_len > sizeof(fs_dev_label)) { printf("mfs:fs_readsuper: label too long\n"); return EINVAL; } r= sys_safecopyfrom(fs_m_in.m_source, label_gid, 0, (vir_bytes)fs_dev_label, label_len, D); if (r != OK) { printf("mfs:fs_readsuper: safecopyfrom failed: %d\n", r); return EINVAL; } r= ds_retrieve_u32(fs_dev_label, &tasknr); if (r != OK) { printf("mfs:fs_readsuper: ds_retrieve_u32 failed for '%s': %d\n", fs_dev_label, r); return EINVAL; } driver_e= tasknr; /* Map the driver endpoint for this major */ driver_endpoints[(fs_dev >> MAJOR) & BYTE].driver_e = driver_e; use_getuptime2= TRUE; /* Should be removed with old * getuptime call. */ vfs_slink_storage = (char *)0xdeadbeef; /* Should be removed together * with old lookup code. */; /* Open the device the file system lives on. */ if (dev_open(driver_e, fs_dev, driver_e, fs_m_in.REQ_READONLY ? R_BIT : (R_BIT|W_BIT)) != OK) { return(EINVAL); } /* Fill in the super block. */ superblock.s_dev = fs_dev; /* read_super() needs to know which dev */ r = read_super(&superblock); /* Is it recognized as a Minix filesystem? */ if (r != OK) { superblock.s_dev = NO_DEV; dev_close(driver_e, fs_dev); return(r); } set_blocksize(superblock.s_block_size); /* Get the root inode of the mounted file system. */ if ( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NIL_INODE) { printf("MFS: couldn't get root inode?!\n"); superblock.s_dev = NO_DEV; dev_close(driver_e, fs_dev); return EINVAL; } if (root_ip != NIL_INODE && root_ip->i_mode == 0) { printf("MFS: zero mode for root inode?!\n"); put_inode(root_ip); superblock.s_dev = NO_DEV; dev_close(driver_e, fs_dev); return EINVAL; } superblock.s_rd_only = fs_m_in.REQ_READONLY; superblock.s_is_root = fs_m_in.REQ_ISROOT; /* Root inode properties */ fs_m_out.RES_INODE_NR = root_ip->i_num; fs_m_out.RES_MODE = root_ip->i_mode; fs_m_out.RES_FILE_SIZE = root_ip->i_size; fs_m_out.RES_UID = root_ip->i_uid; fs_m_out.RES_GID = root_ip->i_gid; return r; }