#include <sys/param.h>
#include <sys/mount.h>
#include <sys/disklabel.h>
#include <sys/stat.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <libufs.h>
static int handle_disk_read(struct uufsd *, struct fs *, int);
int
sbread(struct uufsd *disk)
{
struct fs *fs;
int error;
error = sbget(disk->d_fd, &fs, disk->d_sblockloc, disk->d_lookupflags);
return (handle_disk_read(disk, fs, error));
}
int
sbfind(struct uufsd *disk, int flags)
{
struct fs *fs;
int error;
error = sbsearch(disk->d_fd, &fs, flags);
return (handle_disk_read(disk, fs, error));
}
static int
handle_disk_read(struct uufsd *disk, struct fs *fs, int error)
{
ERROR(disk, NULL);
if (error != 0) {
switch (error) {
case EIO:
ERROR(disk, "non-existent or truncated superblock");
break;
case ENOENT:
ERROR(disk, "no usable known superblock found");
break;
case EINTEGRITY:
ERROR(disk, "superblock check-hash failure");
break;
case ENOSPC:
ERROR(disk, "failed to allocate space for superblock "
"information");
break;
case EINVAL:
ERROR(disk, "The previous newfs operation on this "
"volume did not complete.\nYou must complete "
"newfs before using this volume.");
break;
default:
ERROR(disk, "unknown superblock read error");
errno = EIO;
break;
}
disk->d_ufs = 0;
return (-1);
}
memcpy(&disk->d_fs, fs, fs->fs_sbsize);
free(fs);
fs = &disk->d_fs;
if (fs->fs_magic == FS_UFS1_MAGIC)
disk->d_ufs = 1;
if (fs->fs_magic == FS_UFS2_MAGIC)
disk->d_ufs = 2;
disk->d_bsize = fs->fs_fsize / fsbtodb(fs, 1);
disk->d_sblock = fs->fs_sblockloc / disk->d_bsize;
disk->d_si = fs->fs_si;
return (0);
}
int
sbwrite(struct uufsd *disk, int all)
{
struct fs *fs;
int rv;
ERROR(disk, NULL);
rv = ufs_disk_write(disk);
if (rv == -1) {
ERROR(disk, "failed to open disk for writing");
return (-1);
}
fs = &disk->d_fs;
if ((errno = sbput(disk->d_fd, fs, all ? fs->fs_ncg : 0)) != 0) {
switch (errno) {
case EIO:
ERROR(disk, "failed to write superblock");
break;
default:
ERROR(disk, "unknown superblock write error");
errno = EIO;
break;
}
return (-1);
}
return (0);
}
static int use_pread(void *devfd, off_t loc, void **bufp, int size);
static int use_pwrite(void *devfd, off_t loc, void *buf, int size);
int
sbget(int devfd, struct fs **fsp, off_t sblockloc, int flags)
{
int error;
error = ffs_sbget(&devfd, fsp, sblockloc, flags, "user", use_pread);
fflush(NULL);
return (error);
}
int
sbsearch(int devfd, struct fs **fsp, int flags)
{
int error;
error = ffs_sbsearch(&devfd, fsp, flags, "user", use_pread);
fflush(NULL);
return (error);
}
static int
use_pread(void *devfd, off_t loc, void **bufp, int size)
{
int fd;
fd = *(int *)devfd;
BUF_MALLOC(bufp, NULL, size);
if (*bufp == NULL)
return (ENOSPC);
if (pread(fd, *bufp, size, loc) != size)
return (EIO);
return (0);
}
int
sbput(int devfd, struct fs *fs, int numaltwrite)
{
struct csum *savedcsp;
off_t savedactualloc;
int i, error;
error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, use_pwrite);
fflush(NULL);
if (error != 0 || numaltwrite == 0)
return (error);
savedactualloc = fs->fs_sblockactualloc;
if (fs->fs_si != NULL) {
savedcsp = fs->fs_csp;
fs->fs_csp = NULL;
}
for (i = 0; i < numaltwrite; i++) {
fs->fs_sblockactualloc = dbtob(fsbtodb(fs, cgsblock(fs, i)));
if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc,
use_pwrite)) != 0) {
fflush(NULL);
fs->fs_sblockactualloc = savedactualloc;
fs->fs_csp = savedcsp;
return (error);
}
}
fs->fs_sblockactualloc = savedactualloc;
if (fs->fs_si != NULL)
fs->fs_csp = savedcsp;
fflush(NULL);
return (0);
}
static int
use_pwrite(void *devfd, off_t loc, void *buf, int size)
{
int fd;
fd = *(int *)devfd;
if (pwrite(fd, buf, size, loc) != size)
return (EIO);
return (0);
}