pcfs_partition.c revision 18c2aff776a775d34a4c9893a4c72e0434d68e36
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* DOS partition class implementation file
*/
/*
* System include files
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
/*
* Private attribute and method declarations
*/
#include "partition_private.h"
typedef struct pcfs_attributes {
char dos_partition_letterp[2];
/*
* Offset in the volume header of the ascii name of the volume.
* This is only valid for dos 4.0 and later.
*/
#define DOS_NAME_OFFSET 0x2b
/*
* Number of bytes in the "volume header" located in sector
* 0 on a DOS disk. Used to calculate the checksum.
*/
#define DOS_LABLEN 0x3e
/*
* Number of bytes to read from a DOS disk
*/
/*
* Mask used to compute the offset of a DOS FAT within a sector
*/
/*
* Volume name used for the first PCFS partition on a medium
* that contains other file systems and whose PCFS file
* system has no label
*/
#define UNNAMED_PCFS "unnamed_pcfs"
/*
* Forward declarations of private methods
*/
static bool_t dos_filename_char(char);
static int dos_label_char(int);
static void find_parent_pcfs_vvnodes(partition_private_t *);
static partition_result_t
static partition_result_t
/*
* Methods that implement abstract methods
* declared in the parent partition class
*/
static partition_methods_t partition_methods =
/*
* Definition of the public read_partition() method that
* identifies the partition type and sets its attributes
*/
{
/*
* If there's a readable PCFS label on the partition,
* set the partition's attributes and return PARTITION_SUCCESS.
*/
goto dun;
}
if (partition_result == PARTITION_SUCCESS) {
malloc(sizeof (pcfs_attributes_t));
}
}
if (partition_result == PARTITION_SUCCESS) {
#ifdef i386
#else
#endif
if ((parent_privatep != NULL) &&
/*
* The partition is a subpartition of a parent
* partition. The read_slices() method has
* already assigned the partition a devmap index,
* partition_number, and volume name. Transfer
* the volume name to the partition's label.
* Don't increment the medium's PCFS partition
* counter. It's only used to count the number
* of top level PCFS partitions on the medium.
*/
}
} else {
/*
* This is a top level PCFS partition. It
* could be the only top level PCFS partition
* on the medium, the first of several, or
* one of several but not the first. If there
* are several top level PCFS partitions on the
* medium, the create_pcfs_vnodes() method will
* create a directory structure to contain them.
* Set the partition's PCFS partition number and
* the medium's top level PCFS partition counter
* so the create_pcfs_vnodes() method will create
* the correct directory structure.
*/
if (partition_privatep->partition_number == 0) {
/*
* This is the first top level PCFS partition
* on the medium. Set the partition's state
* to mountable. Set the medium's first
* PCFS partition address attribute to the
* address of this partition and increment
* the medium's file system type count.
*/
} else {
}
}
}
if (partition_result == PARTITION_SUCCESS) {
/*
* The DOS partition letter isn't used if the partition
* is a subpartition, but the create_pcfs_volume()
* method expects it to be set anyway.
*/
}
if ((partition_result != PARTITION_SUCCESS) &&
}
dun:
return (partition_result);
}
/*
* Definitions of private methods
*/
static partition_result_t
{
fat_bufferp = NULL;
fat_offset_in_bytes = 0;
fat_offset_in_sector = 0;
offset_to_fat_sector = 0;
if (fat_bufferp == NULL) {
}
if (partition_result == PARTITION_SUCCESS) {
if ((offset_to_fat_sector + DOS_READ_LENGTH) >
}
if ((partition_result == PARTITION_SUCCESS) &&
}
if ((partition_result == PARTITION_SUCCESS) &&
DOS_READ_LENGTH) != DOS_READ_LENGTH)) {
}
if (partition_result == PARTITION_SUCCESS) {
if ((fat_bufferp[fat_offset_in_sector] !=
label_bufferp[PCB_MEDIA]) ||
!= (uchar_t)0xff) ||
!= (uchar_t)0xff)) {
}
}
}
if (fat_bufferp != NULL) {
}
return (partition_result);
}
static partition_result_t
{
/*
* Look for the identifying jump instructions in the label
* buffer. If they're not there return PARTITION_NOT_THIS_TYPE.
* Find the PCFS FAT. Check for 0Xff characters in the second
* and third bytes of the FAT. If they're not there return
* PARTITION_NOT_THIS_TYPE.
*/
}
if (partition_result == PARTITION_SUCCESS) {
}
return (partition_result);
}
static partition_result_t
{
char *name_bufferp;
int raw_pathname_length;
int type_index;
name_bufferp = NULL;
raw_pathname_length = 0;
if (name_bufferp == NULL) {
}
if ((partition_result == PARTITION_SUCCESS) &&
(partition_privatep->partition_number == 0) &&
/*
* This is the first of several top level PCFS partitions
* on the medium. The create_top_level_pcfs_vnodes()
* method has already created pathnames for it that end
* in its volume name. Add a slash and the partition's
* DOS partition letter to each pathname to distinguish
* its pathnames from those of the other top level PCFS
* partitions.
*/
}
}
if ((partition_result == PARTITION_SUCCESS) &&
(partition_privatep->partition_number > 0)) {
/*
* This is a top level PCFS partition, but not
* the first one on the medium. Copy the first
* top level PCFS partition's pathnames to this
* partition's pathnames, and replace the first
* partition's DOS partition letter in the pathnames
* with this partition's DOS partition letter.
*/
(void) strncpy(name_bufferp,
(block_pathname_length - 1));
(void) strcat(name_bufferp,
}
(void) strncpy(name_bufferp,
(raw_pathname_length - 1));
(void) strcat(name_bufferp,
}
if ((partition_result == PARTITION_SUCCESS) &&
/*
* This is a PCFS subpartition of a parent partition
* (a slice.) The generic create_pathnames() method
* will create the correct pathnames for it.
*/
}
}
if (name_bufferp != NULL) {
}
return (partition_result);
}
static partition_result_t
{
/*
* Only called for the first top level PCFS partition
* on the medium.
*/
char *filenamep;
char *name_bufferp;
char *pcfs_dirnamep;
char *raw_pathnamep;
int type_index;
name_bufferp = NULL;
if (name_bufferp == NULL) {
}
if ((partition_result == PARTITION_SUCCESS) &&
/*
* There are at least two top level PCFS partitions on
* the medium. Find the pathname of the directory that
* contains them.
*/
(void) strncpy(name_bufferp,
if (pcfs_dirnamep == NULL) {
}
}
if ((partition_result == PARTITION_SUCCESS) &&
/*
* There's only one top level PCFS partition on the medium.
* directory, give it the symbolic name of the device in
* which the medium is inserted, and link it to the raw
* vvnode of the partition.
*/
NULL);
}
if ((partition_result == PARTITION_SUCCESS) &&
/*
* There are at least two top level PCFS partitions on the
* medium. Create the symbolic link in the
* of the device in which the medium is inserted, and link
* it to the vnode of the directory containing the top
* level PCFS partitions.
*/
NULL);
}
if (name_bufferp != NULL) {
}
if (pcfs_dirnamep != NULL) {
}
return (partition_result);
}
static partition_result_t
{
/*
* NOTE: The file system structure that this method
* creates is a legacy public interface between
* the volume manager and user-level applications.
* Changing it will cause those applications to fail.
*/
int type_index;
(partition_privatep->partition_number == 0) &&
/*
* This is the first top level PCFS partition on
* the medium, and it doesn't have a volume name.
* Give it a volume name that distinguishes it from
* the partitions containing other file systems.
*/
}
}
if ((partition_result == PARTITION_SUCCESS) &&
(partition_privatep->partition_number == 0)) {
/*
* This is the first top level PCFS partition on the
* medium. Create top level vnodes for it. If there
* are several top level PCFS partitions on the medium
* the convert_vnodes_to_parent_vnodes() and
* create_slice_vvnodes() methods will create a
* directory structure for them.
*/
}
if (partition_result == PARTITION_SUCCESS) {
}
if ((partition_result == PARTITION_SUCCESS) &&
(partition_privatep->partition_number > 0))) {
/*
* This isn't the first top level PCFS partition on
* the medium. The create_top_level_pcfs_vnodes()
* method has already created a volume object for
* that partition.
*/
}
/*
* If the partition is one of several top level PCFS partitions
* on the medium, or if it is a slice, find or create its parent
* vnodes and add slice vnodes for the partition to the parent
* vnodes.
*/
if ((partition_result == PARTITION_SUCCESS) &&
(partition_privatep->partition_number == 0) &&
/*
* This is the first of several top level PCFS
* partitions on the medium. Convert its vnodes
* into directory vnodes and make them its parent
* vnodes. The create_pcfs_pathnames(),
* create_pcfs_volume(), and create_slice_vvnodes()
* methods attach slice vnodes for all the top
* level PCFS partitions, including the first one,
* to the parent vnodes.
*/
}
if ((partition_result == PARTITION_SUCCESS) &&
(partition_privatep->partition_number > 0)) {
/*
* This is one of several top level PCFS partitions
* on the medium, but not the first. Find the
* parent vvnodes created for the first top level
* PCFS partition and write their addresses to the
* partition's parent vvnode address attributes.
*/
}
if ((partition_result == PARTITION_SUCCESS) &&
/*
* This partition is a subpartition of another
* partition, and its parent vvnodes are that
* partition's vvnodes.
*/
}
if ((partition_result == PARTITION_SUCCESS) &&
/*
* This partition is either a subpartition of another
* partition or it's one of several top level PCFS
* partitions on the medium. Create slice vvnodes for
* it beneath its parent vvnodes.
*/
}
if (partition_result == PARTITION_SUCCESS) {
}
if ((partition_result == PARTITION_SUCCESS) &&
(partition_privatep->partition_number == 0)) {
/*
* Only create a symlink to the first top level PCFS
* partition on the medium.
*/
}
return (partition_result);
}
static partition_result_t
{
if (partition_result == PARTITION_SUCCESS) {
}
return (partition_result);
}
static partition_result_t
{
/*
* Only called for the first top level PCFS partition
* on the medium.
*/
if (partition_result == PARTITION_SUCCESS) {
}
if (partition_result == PARTITION_SUCCESS) {
if (parent_privatep != NULL) {
/*
* This partition has a parent fdisk partition.
* Its parent vvnodes are the fdisk partition's
* vvnodes.
*/
} else {
/*
* This is the only partition on the
* medium. Its parent vvnodes are
* the medium's vvnodes.
*/
}
}
if (partition_result == PARTITION_SUCCESS) {
}
return (partition_result);
}
static partition_result_t
{
int dest_index;
int source_index;
int test_char;
char *volume_namep;
dest_index = 0;
source_index = 0;
volume_namep = NULL;
if (volume_namep == NULL) {
}
if (partition_result == PARTITION_SUCCESS) {
source_index = 0;
dest_index = 0;
(source_index < PCFNAMESIZE)) {
dest_index++;
source_index++;
}
source_index = 0;
(source_index < PCFEXTSIZE)) {
dest_index++;
source_index++;
}
/*
* Reset the destination string index to the last character
* in the volume name string, and strip off any trailing
* underscore characters that might have been added by
* dos_label_char().
*/
dest_index--;
dest_index--;
}
dest_index++;
}
return (partition_result);
}
static bool_t
dos_filename_char(char c)
{
/*
* copied from pc_validchar() in the kernel
*
* isdigit(), isupper(), ..., aren't used because they're
* character-set-dependent, but DOS isn't
*/
static char valid_chars[] = {
"$#&@!%()-{}<>`_\\^~|'"
};
char *charp;
/*
* Should be "$#&@!%()-{}`_^~' " ??
* From experiment in DOSWindows, "*+=|\[];:\",<>.?/" are illegal.
* See IBM DOS4.0 Tech Ref. B-57.
*/
charp = valid_chars;
if ((c >= 'A') && (c <= 'Z')) {
} else if ((c >= '0') && (c <= '9')) {
} else {
charp = valid_chars;
if (c == *charp) {
}
charp++;
}
}
return (is_valid);
}
static int
dos_label_char(int c)
{
int return_char;
return_char = NULLC;
if (isalnum(c)) {
return_char = c;
} else if (isspace(c)) {
return_char = '_';
} else {
switch (c) {
case '.':
case '_':
case '+':
return_char = c;
break;
default:
return_char = NULLC;
}
}
return (return_char);
}
static void
{
/*
* Set the partition's parent vvnode address attributes
* to the parent vvnode addresses of the first PCFS
* partition on the medium.
*/
}
static partition_result_t
{
if (label_bufferp == NULL) {
}
if (partition_result == PARTITION_SUCCESS &&
}
if ((partition_result == PARTITION_SUCCESS) &&
}
if ((partition_result == PARTITION_SUCCESS) &&
DOS_READ_LENGTH) != DOS_READ_LENGTH)) {
}
if (partition_result == PARTITION_SUCCESS) {
}
if (partition_result == PARTITION_SUCCESS) {
}
if (label_bufferp != NULL) {
}
return (partition_result);
}
static partition_result_t
{
char *name_bufferp;
name_bufferp = NULL;
} else {
}
if ((partition_result == PARTITION_SUCCESS) &&
} else if (partition_result == PARTITION_SUCCESS) {
if (name_bufferp == NULL) {
} else {
}
}
}
if (name_bufferp != NULL) {
}
return (partition_result);
}
static partition_result_t
{
char *volume_namep;
int buffer_offset;
char test_char;
volume_namep = NULL;
}
/*
* Set the buffer offset back to the last character in the
* label.
*/
}
(buffer_offset >= DOS_NAME_OFFSET)) {
}
if (buffer_offset >= DOS_NAME_OFFSET) {
if (volume_namep == NULL) {
} else {
(void) strncpy(volume_namep,
(char *)&label_bufferp[DOS_NAME_OFFSET],
}
}
if (volume_namep != NULL) {
}
}
return (partition_result);
}
static partition_result_t
{
char *volume_namep;
dir_index = 0;
volume_namep = NULL;
}
if (partition_result == PARTITION_SUCCESS) {
}
}
if (partition_result == PARTITION_SUCCESS) {
SEEK_SET) < 0) {
}
}
if (partition_result == PARTITION_SUCCESS) {
(void *)dir_list,
}
}
if (partition_result == PARTITION_SUCCESS) {
dir_index = 0;
volume_namep = NULL;
while ((volume_namep == NULL) &&
(dir_index < num_entries)) {
PCD_ERASED) &&
PCDL_LFN_BITS) &&
&volume_namep);
}
dir_index++;
}
}
}
}
}
return (partition_result);
}
static partition_result_t
{
char *key_bufferp;
key_bufferp = NULL;
if (key_bufferp == NULL) {
}
if (partition_result == PARTITION_SUCCESS) {
}
if (partition_result == PARTITION_SUCCESS) {
}
}
if (partition_result == PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
if (key_bufferp != NULL) {
}
return (partition_result);
}
static partition_result_t
{
static const char dos_partition_letters[] =
{
'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
} else {
}
return (partition_result);
}