/** * @brief Retrieves the detailed information * about a disk volume. * @param[in] volume_letter the volume letter. * @param[in,out] v pointer to structure * receiving the volume information. * @return Zero for success, negative * value otherwise. */ int winx_get_volume_information(char volume_letter,winx_volume_information *v) { HANDLE hRoot; /* check input data correctness */ if(v == NULL) return (-1); /* ensure that it will work on w2k */ volume_letter = winx_toupper(volume_letter); /* reset all fields of the structure, except of volume_letter */ memset(v,0,sizeof(winx_volume_information)); v->volume_letter = volume_letter; if(volume_letter < 'A' || volume_letter > 'Z') return (-1); /* open root directory */ hRoot = OpenRootDirectory(volume_letter); if(hRoot == NULL) return (-1); /* get drive geometry */ if(get_drive_geometry(hRoot,v) < 0){ NtClose(hRoot); return (-1); } /* get the name of contained file system */ if(get_filesystem_name(hRoot,v) < 0){ NtClose(hRoot); return (-1); } /* get name of the volume */ get_volume_label(hRoot,v); /* get NTFS data */ memset(&v->ntfs_data,0,sizeof(NTFS_DATA)); if(!strcmp(v->fs_name,"NTFS")){ if(get_ntfs_data(v) < 0){ etrace("NTFS data is unavailable for %c:", volume_letter); } } /* get dirty flag */ get_volume_dirty_flag(v); NtClose(hRoot); return 0; }
/* ioctl routine */ int vinumioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) { unsigned int objno; int error = 0; struct sd *sd; struct plex *plex; struct volume *vol; unsigned int index; /* for transferring config info */ unsigned int sdno; /* for transferring config info */ int fe; /* free list element number */ struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) data; /* struct to return */ /* First, decide what we're looking at */ switch (DEVTYPE(dev)) { case VINUM_SUPERDEV_TYPE: /* ordinary super device */ ioctl_reply = (struct _ioctl_reply *) data; /* save the address to reply to */ switch (cmd) { #ifdef VINUMDEBUG case VINUM_DEBUG: if (((struct debuginfo *) data)->changeit) /* change debug settings */ debug = (((struct debuginfo *) data)->param); else { if (debug & DEBUG_REMOTEGDB) boothowto |= RB_GDB; /* serial debug line */ else boothowto &= ~RB_GDB; /* local ddb */ Debugger("vinum debug"); } ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */ ioctl_reply->error = 0; return 0; #endif case VINUM_CREATE: /* create a vinum object */ error = lock_config(); /* get the config for us alone */ if (error) /* can't do it, */ return error; /* give up */ error = setjmp(command_fail); /* come back here on error */ if (error == 0) /* first time, */ ioctl_reply->error = parse_user_config((char *) data, /* update the config */ &keyword_set); else if (ioctl_reply->error == 0) { /* longjmp, but no error status */ ioctl_reply->error = EINVAL; /* note that something's up */ ioctl_reply->msg[0] = '\0'; /* no message? */ } unlock_config(); return 0; /* must be 0 to return the real error info */ case VINUM_GETCONFIG: /* get the configuration information */ bcopy(&vinum_conf, data, sizeof(vinum_conf)); return 0; /* start configuring the subsystem */ case VINUM_STARTCONFIG: return start_config(*(int *) data); /* just lock it. Parameter is 'force' */ /* * Move the individual parts of the config to user space. * * Specify the index of the object in the first word of data, * and return the object there */ case VINUM_DRIVECONFIG: index = *(int *) data; /* get the index */ if (index >= (unsigned) vinum_conf.drives_allocated) /* can't do it */ return ENXIO; /* bang */ bcopy(&DRIVE[index], data, sizeof(struct _drive)); /* copy the config item out */ return 0; case VINUM_SDCONFIG: index = *(int *) data; /* get the index */ if (index >= (unsigned) vinum_conf.subdisks_allocated) /* can't do it */ return ENXIO; /* bang */ bcopy(&SD[index], data, sizeof(struct _sd)); /* copy the config item out */ return 0; case VINUM_PLEXCONFIG: index = *(int *) data; /* get the index */ if (index >= (unsigned) vinum_conf.plexes_allocated) /* can't do it */ return ENXIO; /* bang */ bcopy(&PLEX[index], data, sizeof(struct _plex)); /* copy the config item out */ return 0; case VINUM_VOLCONFIG: index = *(int *) data; /* get the index */ if (index >= (unsigned) vinum_conf.volumes_allocated) /* can't do it */ return ENXIO; /* bang */ bcopy(&VOL[index], data, sizeof(struct _volume)); /* copy the config item out */ return 0; case VINUM_PLEXSDCONFIG: index = *(int *) data; /* get the plex index */ sdno = ((int *) data)[1]; /* and the sd index */ if ((index >= (unsigned) vinum_conf.plexes_allocated) /* plex doesn't exist */ ||(sdno >= PLEX[index].subdisks)) /* or it doesn't have this many subdisks */ return ENXIO; /* bang */ bcopy(&SD[PLEX[index].sdnos[sdno]], /* copy the config item out */ data, sizeof(struct _sd)); return 0; /* * We get called in two places: one from the * userland config routines, which call us * to complete the config and save it. This * call supplies the value 0 as a parameter. * * The other place is from the user "saveconfig" * routine, which can only work if we're *not* * configuring. In this case, supply parameter 1. */ case VINUM_SAVECONFIG: if (VFLAGS & VF_CONFIGURING) { /* must be us, the others are asleep */ if (*(int *) data == 0) /* finish config */ finish_config(1); /* finish the configuration and update it */ else return EBUSY; /* can't do it now */ } save_config(); /* save configuration to disk */ return 0; case VINUM_RELEASECONFIG: /* release the config */ if (VFLAGS & VF_CONFIGURING) { /* must be us, the others are asleep */ finish_config(0); /* finish the configuration, don't change it */ save_config(); /* save configuration to disk */ } else error = EINVAL; /* release what config? */ return error; case VINUM_INIT: ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */ ioctl_reply->error = 0; return 0; case VINUM_RESETCONFIG: if (vinum_inactive(0)) { /* if the volumes are not active */ /* * Note the open count. We may be called from v, so we'll be open. * Keep the count so we don't underflow */ free_vinum(1); /* clean up everything */ log(LOG_NOTICE, "vinum: CONFIGURATION OBLITERATED\n"); ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */ ioctl_reply->error = 0; return 0; } return EBUSY; case VINUM_SETSTATE: setstate((struct vinum_ioctl_msg *) data); /* set an object state */ return 0; /* * Set state by force, without changing * anything else. */ case VINUM_SETSTATE_FORCE: setstate_by_force((struct vinum_ioctl_msg *) data); /* set an object state */ return 0; #ifdef VINUMDEBUG case VINUM_MEMINFO: vinum_meminfo(data); return 0; case VINUM_MALLOCINFO: return vinum_mallocinfo(data); case VINUM_RQINFO: return vinum_rqinfo(data); #endif case VINUM_LABEL: /* label a volume */ ioctl_reply->error = write_volume_label(*(int *) data); /* index of the volume to label */ ioctl_reply->msg[0] = '\0'; /* no message */ return 0; case VINUM_REMOVE: remove((struct vinum_ioctl_msg *) data); /* remove an object */ return 0; case VINUM_GETFREELIST: /* get a drive free list element */ index = *(int *) data; /* get the drive index */ fe = ((int *) data)[1]; /* and the free list element */ if ((index >= (unsigned) vinum_conf.drives_allocated) /* plex doesn't exist */ ||(DRIVE[index].state == drive_unallocated)) return ENODEV; if (fe >= DRIVE[index].freelist_entries) /* no such entry */ return ENOENT; bcopy(&DRIVE[index].freelist[fe], data, sizeof(struct drive_freelist)); return 0; case VINUM_RESETSTATS: resetstats((struct vinum_ioctl_msg *) data); /* reset object stats */ return 0; /* attach an object to a superordinate object */ case VINUM_ATTACH: attachobject((struct vinum_ioctl_msg *) data); return 0; /* detach an object from a superordinate object */ case VINUM_DETACH: detachobject((struct vinum_ioctl_msg *) data); return 0; /* rename an object */ case VINUM_RENAME: renameobject((struct vinum_rename_msg *) data); return 0; /* replace an object */ case VINUM_REPLACE: replaceobject((struct vinum_ioctl_msg *) data); return 0; case VINUM_DAEMON: vinum_daemon(); /* perform the daemon */ return 0; case VINUM_FINDDAEMON: /* check for presence of daemon */ return vinum_finddaemon(); return 0; case VINUM_SETDAEMON: /* set daemon flags */ return vinum_setdaemonopts(*(int *) data); case VINUM_GETDAEMON: /* get daemon flags */ *(int *) data = daemon_options; return 0; case VINUM_PARITYOP: /* check/rebuild RAID-4/5 parity */ parityops((struct vinum_ioctl_msg *) data); return 0; /* move an object */ case VINUM_MOVE: moveobject((struct vinum_ioctl_msg *) data); return 0; default: /* FALLTHROUGH */ break; } case VINUM_DRIVE_TYPE: default: log(LOG_WARNING, "vinumioctl: invalid ioctl from process %d (%s): %lx\n", curthread->td_proc->p_pid, curthread->td_proc->p_comm, cmd); return EINVAL; case VINUM_SD_TYPE: case VINUM_RAWSD_TYPE: objno = Sdno(dev); sd = &SD[objno]; switch (cmd) { case DIOCGDINFO: /* get disk label */ get_volume_label(sd->name, 1, sd->sectors, (struct disklabel *) data); break; /* * We don't have this stuff on hardware, * so just pretend to do it so that * utilities don't get upset. */ case DIOCWDINFO: /* write partition info */ case DIOCSDINFO: /* set partition info */ return 0; /* not a titty */ default: return ENOTTY; /* not my kind of ioctl */ } return 0; /* pretend we did it */ case VINUM_RAWPLEX_TYPE: case VINUM_PLEX_TYPE: objno = Plexno(dev); plex = &PLEX[objno]; switch (cmd) { case DIOCGDINFO: /* get disk label */ get_volume_label(plex->name, 1, plex->length, (struct disklabel *) data); break; /* * We don't have this stuff on hardware, * so just pretend to do it so that * utilities don't get upset. */ case DIOCWDINFO: /* write partition info */ case DIOCSDINFO: /* set partition info */ return 0; /* not a titty */ default: return ENOTTY; /* not my kind of ioctl */ } return 0; /* pretend we did it */ case VINUM_VOLUME_TYPE: objno = Volno(dev); if ((unsigned) objno >= (unsigned) vinum_conf.volumes_allocated) /* not a valid volume */ return ENXIO; vol = &VOL[objno]; if (vol->state != volume_up) /* not up, */ return EIO; /* I/O error */ switch (cmd) { case DIOCGMEDIASIZE: *(off_t *)data = vol->size << DEV_BSHIFT; break; case DIOCGSECTORSIZE: *(u_int *)data = DEV_BSIZE; break; /* * We don't have this stuff on hardware, * so just pretend to do it so that * utilities don't get upset. */ case DIOCWDINFO: /* write partition info */ case DIOCSDINFO: /* set partition info */ return 0; /* not a titty */ case DIOCWLABEL: /* set or reset label writeable */ if ((flag & FWRITE) == 0) /* not writeable? */ return EACCES; /* no, die */ if (*(int *) data != 0) /* set it? */ vol->flags |= VF_WLABEL; /* yes */ else vol->flags &= ~VF_WLABEL; /* no, reset */ break; default: return ENOTTY; /* not my kind of ioctl */ } break; } return 0; /* XXX */ }