Edit

IABSD.fr/src/sbin/fdisk/disk.c

Branch :

  • Show log

    Commit

  • Author : krw
    Date : 2022-04-25 17:10:09
    Hash : adf35c80
    Message : Push DISK_[read|write]sectors() down to disk.c local functions and expose new DISK_[read|write]bytes() functions. Eliminates many bytes <-> sector i/o dances and makes the code much easier to understand. Be a bit more careful to consistently write only bytes that checksums are calculated over. No intentional functional change.

  • sbin/fdisk/disk.c
  • /*	$OpenBSD: disk.c,v 1.75 2022/04/25 17:10:09 krw Exp $	*/
    
    /*
     * Copyright (c) 1997 Tobias Weingartner
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    
    #include <sys/param.h>		/* DEV_BSIZE */
    #include <sys/ioctl.h>
    #include <sys/dkio.h>
    #include <sys/stat.h>
    #include <sys/disklabel.h>
    
    #include <err.h>
    #include <fcntl.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <util.h>
    
    #include "part.h"
    #include "disk.h"
    #include "misc.h"
    
    struct disk		disk;
    struct disklabel	dl;
    
    char		*readsectors(const uint64_t, const uint32_t);
    int		 writesectors(const void *, const uint64_t, const uint32_t);
    
    void
    DISK_open(const char *name, const int oflags)
    {
    	struct stat		st;
    	uint64_t		ns, bs, sz, spc;
    
    	disk.dk_name = strdup(name);
    	if (disk.dk_name == NULL)
    		err(1, "dk_name");
    	disk.dk_fd = opendev(disk.dk_name, oflags, OPENDEV_PART, NULL);
    	if (disk.dk_fd == -1)
    		err(1, "opendev('%s', 0x%x)", disk.dk_name, oflags);
    	if (fstat(disk.dk_fd, &st) == -1)
    		err(1, "fstat('%s)", disk.dk_name);
    	if (!S_ISCHR(st.st_mode))
    		errx(1, "%s is not a character device", disk.dk_name);
    	if (ioctl(disk.dk_fd, DIOCGPDINFO, &dl) == -1)
    		err(1, "DIOCGPDINFO");
    
    	/* Set geometry to use in MBR partitions. */
    	if (disk.dk_size > 0) {
    		/* -l has set disk size. */
    		sz = disk.dk_size;
    		disk.dk_heads = 1;
    		disk.dk_sectors = 64;
    		disk.dk_size = DL_BLKTOSEC(&dl, sz);
    		disk.dk_cylinders = disk.dk_size / disk.dk_sectors;
    	} else if (disk.dk_cylinders > 0) {
    		/* -c/-h/-s has set disk geometry & therefore size. */
    		sz = disk.dk_cylinders * disk.dk_heads * disk.dk_sectors;
    		disk.dk_size = DL_BLKTOSEC(&dl, sz);
    		disk.dk_sectors = DL_BLKTOSEC(&dl, disk.dk_sectors);
    	} else {
    		disk.dk_cylinders = dl.d_ncylinders;
    		disk.dk_heads = dl.d_ntracks;
    		disk.dk_sectors = dl.d_nsectors;
    		/* MBR handles only first UINT32_MAX sectors. */
    		spc = (uint64_t)disk.dk_heads * disk.dk_sectors;
    		sz = DL_GETDSIZE(&dl);
    		if (sz > UINT32_MAX) {
    			disk.dk_cylinders = UINT32_MAX / spc;
    			disk.dk_size = disk.dk_cylinders * spc;
    		} else
    			disk.dk_size = sz;
    	}
    
    	if (disk.dk_size == 0)
    		errx(1, "disk size is 0");
    
    	if (disk.dk_bootprt.prt_ns > 0) {
    		ns = disk.dk_bootprt.prt_ns + DL_BLKSPERSEC(&dl) - 1;
    		bs = disk.dk_bootprt.prt_bs + DL_BLKSPERSEC(&dl) - 1;
    		disk.dk_bootprt.prt_ns = DL_BLKTOSEC(&dl, ns);
    		disk.dk_bootprt.prt_bs = DL_BLKTOSEC(&dl, bs);
    	}
    }
    
    void
    DISK_printgeometry(const char *units)
    {
    	const struct unit_type	*ut;
    	const int		 secsize = dl.d_secsize;
    	double			 size;
    
    	size = units_size(units, disk.dk_size, &ut);
    	printf("Disk: %s\tgeometry: %d/%d/%d [%.0f ", disk.dk_name,
    	    disk.dk_cylinders, disk.dk_heads, disk.dk_sectors, size);
    	if (ut->ut_conversion == 0 && secsize != DEV_BSIZE)
    		printf("%d-byte ", secsize);
    	printf("%s]\n", ut->ut_lname);
    }
    
    /*
     * The caller must free() the returned memory!
     */
    char *
    readsectors(const uint64_t sector, const uint32_t count)
    {
    	char			*secbuf;
    	ssize_t			 len;
    	off_t			 off, where;
    	size_t			 bytes;
    
    	where = sector * dl.d_secsize;
    	bytes = count * dl.d_secsize;
    
    	off = lseek(disk.dk_fd, where, SEEK_SET);
    	if (off == -1) {
    #ifdef DEBUG
    		warn("lseek(%lld) for read", (int64_t)where);
    #endif
    		return NULL;
    	}
    
    	secbuf = calloc(1, bytes);
    	if (secbuf == NULL)
    		return NULL;
    
    	len = read(disk.dk_fd, secbuf, bytes);
    	if (len == -1) {
    #ifdef DEBUG
    		warn("read(%zu @ %lld)", bytes, (int64_t)where);
    #endif
    		free(secbuf);
    		return NULL;
    	}
    	if (len != (ssize_t)bytes) {
    #ifdef DEBUG
    		warnx("short read(%zu @ %lld)", bytes, (int64_t)where);
    #endif
    		free(secbuf);
    		return NULL;
    	}
    
    	return secbuf;
    }
    
    int
    writesectors(const void *buf, const uint64_t sector, const uint32_t count)
    {
    	ssize_t			len;
    	off_t			off, where;
    	size_t			bytes;
    
    	where = sector * dl.d_secsize;
    	bytes = count * dl.d_secsize;
    
    	off = lseek(disk.dk_fd, where, SEEK_SET);
    	if (off == -1) {
    #ifdef DEBUG
    		warn("lseek(%lld) for write", (int64_t)where);
    #endif
    		return -1;
    	}
    
    	len = write(disk.dk_fd, buf, bytes);
    	if (len == -1) {
    #ifdef DEBUG
    		warn("write(%zu @ %lld)", bytes, (int64_t)where);
    #endif
    		return -1;
    	}
    	if (len != (ssize_t)bytes) {
    #ifdef DEBUG
    		warnx("short write(%zu @ %lld)", bytes, (int64_t)where);
    #endif
    		return -1;
    	}
    
    	return 0;
    }
    
    int
    DISK_readbytes(void *buf, const uint64_t sector, const size_t sz)
    {
    	char			*secbuf;
    	uint32_t		 count;
    
    	count = (sz + dl.d_secsize - 1) / dl.d_secsize;
    
    	secbuf = readsectors(sector, count);
    	if (secbuf == NULL)
    		return -1;
    
    	memcpy(buf, secbuf, sz);
    	free(secbuf);
    
    	return 0;
    }
    
    int
    DISK_writebytes(const void *buf, const uint64_t sector, const size_t sz)
    {
    	char 			*secbuf;
    	uint32_t		 count;
    	int			 rslt;
    
    	count = (sz + dl.d_secsize - 1) / dl.d_secsize;
    
    	secbuf = readsectors(sector, count);
    	if (secbuf == NULL)
    		return -1;
    
    	memcpy(secbuf, buf, sz);
    	rslt = writesectors(secbuf, sector, count);
    	free(secbuf);
    
    	return rslt;
    }