Changeset View
Changeset View
Standalone View
Standalone View
stand/libsa/ufs.c
Show First 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/disklabel.h> | #include <sys/disklabel.h> | ||||
#include <sys/time.h> | #include <sys/time.h> | ||||
#include <ufs/ufs/dinode.h> | #include <ufs/ufs/dinode.h> | ||||
#include <ufs/ufs/dir.h> | #include <ufs/ufs/dir.h> | ||||
#include <ufs/ffs/fs.h> | #include <ufs/ffs/fs.h> | ||||
#include "stand.h" | #include "stand.h" | ||||
#include "disk.h" | |||||
#include "string.h" | #include "string.h" | ||||
static int ufs_open(const char *path, struct open_file *f); | static int ufs_open(const char *path, struct open_file *f); | ||||
static int ufs_write(struct open_file *f, const void *buf, size_t size, | static int ufs_write(struct open_file *f, const void *buf, size_t size, | ||||
size_t *resid); | size_t *resid); | ||||
static int ufs_close(struct open_file *f); | static int ufs_close(struct open_file *f); | ||||
static int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid); | static int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid); | ||||
static off_t ufs_seek(struct open_file *f, off_t offset, int where); | static off_t ufs_seek(struct open_file *f, off_t offset, int where); | ||||
static int ufs_stat(struct open_file *f, struct stat *sb); | static int ufs_stat(struct open_file *f, struct stat *sb); | ||||
static int ufs_readdir(struct open_file *f, struct dirent *d); | static int ufs_readdir(struct open_file *f, struct dirent *d); | ||||
static int ufs_mount(const char *dev, const char *path, void **data); | |||||
static int ufs_unmount(const char *dev, void *data); | |||||
struct fs_ops ufs_fsops = { | struct fs_ops ufs_fsops = { | ||||
"ufs", | .fs_name = "ufs", | ||||
ufs_open, | .fo_open = ufs_open, | ||||
ufs_close, | .fo_close = ufs_close, | ||||
ufs_read, | .fo_read = ufs_read, | ||||
ufs_write, | .fo_write = ufs_write, | ||||
ufs_seek, | .fo_seek = ufs_seek, | ||||
ufs_stat, | .fo_stat = ufs_stat, | ||||
ufs_readdir | .fo_readdir = ufs_readdir, | ||||
.fo_mount = ufs_mount, | |||||
.fo_unmount = ufs_unmount | |||||
}; | }; | ||||
/* | /* | ||||
* In-core open file. | * In-core open file. | ||||
*/ | */ | ||||
struct file { | struct file { | ||||
off_t f_seekp; /* seek pointer */ | off_t f_seekp; /* seek pointer */ | ||||
struct fs *f_fs; /* pointer to super-block */ | struct fs *f_fs; /* pointer to super-block */ | ||||
Show All 13 Lines | struct file { | ||||
char *f_buf; /* buffer for data block */ | char *f_buf; /* buffer for data block */ | ||||
size_t f_buf_size; /* size of data block */ | size_t f_buf_size; /* size of data block */ | ||||
int f_inumber; /* inumber */ | int f_inumber; /* inumber */ | ||||
}; | }; | ||||
#define DIP(fp, field) \ | #define DIP(fp, field) \ | ||||
((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \ | ((fp)->f_fs->fs_magic == FS_UFS1_MAGIC ? \ | ||||
(fp)->f_di.di1.field : (fp)->f_di.di2.field) | (fp)->f_di.di1.field : (fp)->f_di.di2.field) | ||||
typedef struct ufs_mnt { | |||||
char *um_dev; | |||||
int um_fd; | |||||
STAILQ_ENTRY(ufs_mnt) um_link; | |||||
} ufs_mnt_t; | |||||
typedef STAILQ_HEAD(ufs_mnt_list, ufs_mnt) ufs_mnt_list_t; | |||||
static ufs_mnt_list_t mnt_list = STAILQ_HEAD_INITIALIZER(mnt_list); | |||||
static int read_inode(ino_t, struct open_file *); | static int read_inode(ino_t, struct open_file *); | ||||
static int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *); | static int block_map(struct open_file *, ufs2_daddr_t, ufs2_daddr_t *); | ||||
static int buf_read_file(struct open_file *, char **, size_t *); | static int buf_read_file(struct open_file *, char **, size_t *); | ||||
static int buf_write_file(struct open_file *, const char *, size_t *); | static int buf_write_file(struct open_file *, const char *, size_t *); | ||||
static int search_directory(char *, struct open_file *, ino_t *); | static int search_directory(char *, struct open_file *, ino_t *); | ||||
static int ufs_use_sa_read(void *, off_t, void **, int); | static int ufs_use_sa_read(void *, off_t, void **, int); | ||||
/* from ffs_subr.c */ | /* from ffs_subr.c */ | ||||
int ffs_sbget(void *, struct fs **, off_t, char *, | int ffs_sbget(void *, struct fs **, off_t, char *, | ||||
int (*)(void *, off_t, void **, int)); | int (*)(void *, off_t, void **, int)); | ||||
/* | /* | ||||
* Request standard superblock location in ffs_sbget | * Request standard superblock location in ffs_sbget | ||||
*/ | */ | ||||
#define STDSB -1 /* Fail if check-hash is bad */ | #define STDSB -1 /* Fail if check-hash is bad */ | ||||
#define STDSB_NOHASHFAIL -2 /* Ignore check-hash failure */ | #define STDSB_NOHASHFAIL -2 /* Ignore check-hash failure */ | ||||
/* | /* | ||||
* Read a new inode into a file structure. | * Read a new inode into a file structure. | ||||
*/ | */ | ||||
static int | static int | ||||
read_inode(inumber, f) | read_inode(ino_t inumber, struct open_file *f) | ||||
ino_t inumber; | |||||
struct open_file *f; | |||||
{ | { | ||||
struct file *fp = (struct file *)f->f_fsdata; | struct file *fp = (struct file *)f->f_fsdata; | ||||
struct fs *fs = fp->f_fs; | struct fs *fs = fp->f_fs; | ||||
char *buf; | char *buf; | ||||
size_t rsize; | size_t rsize; | ||||
int rc; | int rc; | ||||
if (fs == NULL) | if (fs == NULL) | ||||
Show All 38 Lines | out: | ||||
return (rc); | return (rc); | ||||
} | } | ||||
/* | /* | ||||
* Given an offset in a file, find the disk block number that | * Given an offset in a file, find the disk block number that | ||||
* contains that block. | * contains that block. | ||||
*/ | */ | ||||
static int | static int | ||||
block_map(f, file_block, disk_block_p) | block_map(struct open_file *f, ufs2_daddr_t file_block, | ||||
struct open_file *f; | ufs2_daddr_t *disk_block_p) | ||||
ufs2_daddr_t file_block; | |||||
ufs2_daddr_t *disk_block_p; /* out */ | |||||
{ | { | ||||
struct file *fp = (struct file *)f->f_fsdata; | struct file *fp = (struct file *)f->f_fsdata; | ||||
struct fs *fs = fp->f_fs; | struct fs *fs = fp->f_fs; | ||||
int level; | int level; | ||||
int idx; | int idx; | ||||
ufs2_daddr_t ind_block_num; | ufs2_daddr_t ind_block_num; | ||||
int rc; | int rc; | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | block_map(struct open_file *f, ufs2_daddr_t file_block, | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Write a portion of a file from an internal buffer. | * Write a portion of a file from an internal buffer. | ||||
*/ | */ | ||||
static int | static int | ||||
buf_write_file(f, buf_p, size_p) | buf_write_file(struct open_file *f, const char *buf_p, size_t *size_p) | ||||
struct open_file *f; | |||||
const char *buf_p; | |||||
size_t *size_p; /* out */ | |||||
{ | { | ||||
struct file *fp = (struct file *)f->f_fsdata; | struct file *fp = (struct file *)f->f_fsdata; | ||||
struct fs *fs = fp->f_fs; | struct fs *fs = fp->f_fs; | ||||
long off; | long off; | ||||
ufs_lbn_t file_block; | ufs_lbn_t file_block; | ||||
ufs2_daddr_t disk_block; | ufs2_daddr_t disk_block; | ||||
size_t block_size; | size_t block_size; | ||||
int rc; | int rc; | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | buf_write_file(struct open_file *f, const char *buf_p, size_t *size_p) | ||||
return (rc); | return (rc); | ||||
} | } | ||||
/* | /* | ||||
* Read a portion of a file into an internal buffer. Return | * Read a portion of a file into an internal buffer. Return | ||||
* the location in the buffer and the amount in the buffer. | * the location in the buffer and the amount in the buffer. | ||||
*/ | */ | ||||
static int | static int | ||||
buf_read_file(f, buf_p, size_p) | buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) | ||||
struct open_file *f; | |||||
char **buf_p; /* out */ | |||||
size_t *size_p; /* out */ | |||||
{ | { | ||||
struct file *fp = (struct file *)f->f_fsdata; | struct file *fp = (struct file *)f->f_fsdata; | ||||
struct fs *fs = fp->f_fs; | struct fs *fs = fp->f_fs; | ||||
long off; | long off; | ||||
ufs_lbn_t file_block; | ufs_lbn_t file_block; | ||||
ufs2_daddr_t disk_block; | ufs2_daddr_t disk_block; | ||||
size_t block_size; | size_t block_size; | ||||
int rc; | int rc; | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Search a directory for a name and return its | * Search a directory for a name and return its | ||||
* i_number. | * i_number. | ||||
*/ | */ | ||||
static int | static int | ||||
search_directory(name, f, inumber_p) | search_directory(char *name, struct open_file *f, ino_t *inumber_p) | ||||
char *name; | |||||
struct open_file *f; | |||||
ino_t *inumber_p; /* out */ | |||||
{ | { | ||||
struct file *fp = (struct file *)f->f_fsdata; | struct file *fp = (struct file *)f->f_fsdata; | ||||
struct direct *dp; | struct direct *dp; | ||||
struct direct *edp; | struct direct *edp; | ||||
char *buf; | char *buf; | ||||
size_t buf_size; | size_t buf_size; | ||||
int namlen, length; | int namlen, length; | ||||
int rc; | int rc; | ||||
Show All 30 Lines | #endif | ||||
} | } | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
/* | /* | ||||
* Open a file. | * Open a file. | ||||
*/ | */ | ||||
static int | static int | ||||
ufs_open(upath, f) | ufs_open(const char *upath, struct open_file *f) | ||||
const char *upath; | |||||
struct open_file *f; | |||||
{ | { | ||||
char *cp, *ncp; | char *cp, *ncp; | ||||
int c; | int c; | ||||
ino_t inumber, parent_inumber; | ino_t inumber, parent_inumber; | ||||
struct file *fp; | struct file *fp; | ||||
struct fs *fs; | struct fs *fs; | ||||
int rc; | int rc; | ||||
int nlinks = 0; | int nlinks = 0; | ||||
char namebuf[MAXPATHLEN+1]; | char namebuf[MAXPATHLEN+1]; | ||||
char *buf = NULL; | char *buf = NULL; | ||||
char *path = NULL; | char *path = NULL; | ||||
const char *dev; | |||||
ufs_mnt_t *mnt; | |||||
/* allocate file system specific data structure */ | /* allocate file system specific data structure */ | ||||
fp = malloc(sizeof(struct file)); | fp = malloc(sizeof(struct file)); | ||||
bzero(fp, sizeof(struct file)); | bzero(fp, sizeof(struct file)); | ||||
f->f_fsdata = (void *)fp; | f->f_fsdata = (void *)fp; | ||||
dev = disk_fmtdev(f->f_devdata); | |||||
STAILQ_FOREACH(mnt, &mnt_list, um_link) { | |||||
if (strcmp(dev, mnt->um_dev) == 0) | |||||
break; | |||||
} | |||||
if (mnt == NULL) { | |||||
/* read super block */ | /* read super block */ | ||||
twiddle(1); | twiddle(1); | ||||
if ((rc = ffs_sbget(f, &fs, STDSB_NOHASHFAIL, "stand", | if ((rc = ffs_sbget(f, &fs, STDSB_NOHASHFAIL, "stand", | ||||
ufs_use_sa_read)) != 0) | ufs_use_sa_read)) != 0) | ||||
goto out; | goto out; | ||||
} else { | |||||
struct open_file *sbf; | |||||
struct file *sfp; | |||||
/* get superblock from mounted file system */ | |||||
sbf = fd2open_file(mnt->um_fd); | |||||
sfp = sbf->f_fsdata; | |||||
fs = sfp->f_fs; | |||||
} | |||||
fp->f_fs = fs; | fp->f_fs = fs; | ||||
/* | /* | ||||
* Calculate indirect block levels. | * Calculate indirect block levels. | ||||
*/ | */ | ||||
{ | { | ||||
ufs2_daddr_t mult; | ufs2_daddr_t mult; | ||||
int level; | int level; | ||||
mult = 1; | mult = 1; | ||||
▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | ufs_open(const char *upath, struct open_file *f) | ||||
} | } | ||||
/* | /* | ||||
* Found terminal component. | * Found terminal component. | ||||
*/ | */ | ||||
rc = 0; | rc = 0; | ||||
fp->f_seekp = 0; | fp->f_seekp = 0; | ||||
out: | out: | ||||
if (buf) | |||||
free(buf); | free(buf); | ||||
if (path) | |||||
free(path); | free(path); | ||||
if (rc) { | if (rc) { | ||||
if (fp->f_buf) | |||||
free(fp->f_buf); | free(fp->f_buf); | ||||
if (fp->f_fs != NULL) { | |||||
if (mnt == NULL && fp->f_fs != NULL) { | |||||
free(fp->f_fs->fs_csp); | free(fp->f_fs->fs_csp); | ||||
free(fp->f_fs->fs_si); | free(fp->f_fs->fs_si); | ||||
free(fp->f_fs); | free(fp->f_fs); | ||||
} | } | ||||
free(fp); | free(fp); | ||||
} | } | ||||
return (rc); | return (rc); | ||||
} | } | ||||
Show All 16 Lines | ufs_use_sa_read(void *devfd, off_t loc, void **bufp, int size) | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
if (buf_size != size) | if (buf_size != size) | ||||
return (EIO); | return (EIO); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
ufs_close(f) | ufs_close(struct open_file *f) | ||||
struct open_file *f; | |||||
{ | { | ||||
ufs_mnt_t *mnt; | |||||
struct file *fp = (struct file *)f->f_fsdata; | struct file *fp = (struct file *)f->f_fsdata; | ||||
int level; | int level; | ||||
char *dev; | |||||
f->f_fsdata = (void *)0; | f->f_fsdata = NULL; | ||||
if (fp == (struct file *)0) | if (fp == NULL) | ||||
return (0); | return (0); | ||||
for (level = 0; level < UFS_NIADDR; level++) { | for (level = 0; level < UFS_NIADDR; level++) { | ||||
if (fp->f_blk[level]) | |||||
free(fp->f_blk[level]); | free(fp->f_blk[level]); | ||||
} | } | ||||
if (fp->f_buf) | |||||
free(fp->f_buf); | free(fp->f_buf); | ||||
if (fp->f_fs != NULL) { | |||||
dev = disk_fmtdev(f->f_devdata); | |||||
STAILQ_FOREACH(mnt, &mnt_list, um_link) { | |||||
if (strcmp(dev, mnt->um_dev) == 0) | |||||
break; | |||||
} | |||||
if (mnt == NULL && fp->f_fs != NULL) { | |||||
free(fp->f_fs->fs_csp); | free(fp->f_fs->fs_csp); | ||||
free(fp->f_fs->fs_si); | free(fp->f_fs->fs_si); | ||||
free(fp->f_fs); | free(fp->f_fs); | ||||
} | } | ||||
free(fp); | free(fp); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Copy a portion of a file into kernel memory. | * Copy a portion of a file into kernel memory. | ||||
* Cross block boundaries when necessary. | * Cross block boundaries when necessary. | ||||
*/ | */ | ||||
static int | static int | ||||
ufs_read(f, start, size, resid) | ufs_read(struct open_file *f, void *start, size_t size, size_t *resid) | ||||
struct open_file *f; | |||||
void *start; | |||||
size_t size; | |||||
size_t *resid; /* out */ | |||||
{ | { | ||||
struct file *fp = (struct file *)f->f_fsdata; | struct file *fp = (struct file *)f->f_fsdata; | ||||
size_t csize; | size_t csize; | ||||
char *buf; | char *buf; | ||||
size_t buf_size; | size_t buf_size; | ||||
int rc = 0; | int rc = 0; | ||||
char *addr = start; | char *addr = start; | ||||
Show All 21 Lines | |||||
} | } | ||||
/* | /* | ||||
* Write to a portion of an already allocated file. | * Write to a portion of an already allocated file. | ||||
* Cross block boundaries when necessary. Can not | * Cross block boundaries when necessary. Can not | ||||
* extend the file. | * extend the file. | ||||
*/ | */ | ||||
static int | static int | ||||
ufs_write(f, start, size, resid) | ufs_write(struct open_file *f, const void *start, size_t size, size_t *resid) | ||||
struct open_file *f; | |||||
const void *start; | |||||
size_t size; | |||||
size_t *resid; /* out */ | |||||
{ | { | ||||
struct file *fp = (struct file *)f->f_fsdata; | struct file *fp = (struct file *)f->f_fsdata; | ||||
size_t csize; | size_t csize; | ||||
int rc = 0; | int rc = 0; | ||||
const char *addr = start; | const char *addr = start; | ||||
csize = size; | csize = size; | ||||
while ((size != 0) && (csize != 0)) { | while ((size != 0) && (csize != 0)) { | ||||
Show All 11 Lines | while ((size != 0) && (csize != 0)) { | ||||
size -= csize; | size -= csize; | ||||
} | } | ||||
if (resid) | if (resid) | ||||
*resid = size; | *resid = size; | ||||
return (rc); | return (rc); | ||||
} | } | ||||
static off_t | static off_t | ||||
ufs_seek(f, offset, where) | ufs_seek(struct open_file *f, off_t offset, int where) | ||||
struct open_file *f; | |||||
off_t offset; | |||||
int where; | |||||
{ | { | ||||
struct file *fp = (struct file *)f->f_fsdata; | struct file *fp = (struct file *)f->f_fsdata; | ||||
switch (where) { | switch (where) { | ||||
case SEEK_SET: | case SEEK_SET: | ||||
fp->f_seekp = offset; | fp->f_seekp = offset; | ||||
break; | break; | ||||
case SEEK_CUR: | case SEEK_CUR: | ||||
fp->f_seekp += offset; | fp->f_seekp += offset; | ||||
break; | break; | ||||
case SEEK_END: | case SEEK_END: | ||||
fp->f_seekp = DIP(fp, di_size) - offset; | fp->f_seekp = DIP(fp, di_size) - offset; | ||||
break; | break; | ||||
default: | default: | ||||
errno = EINVAL; | errno = EINVAL; | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return (fp->f_seekp); | return (fp->f_seekp); | ||||
} | } | ||||
static int | static int | ||||
ufs_stat(f, sb) | ufs_stat(struct open_file *f, struct stat *sb) | ||||
struct open_file *f; | |||||
struct stat *sb; | |||||
{ | { | ||||
struct file *fp = (struct file *)f->f_fsdata; | struct file *fp = (struct file *)f->f_fsdata; | ||||
/* only important stuff */ | /* only important stuff */ | ||||
sb->st_mode = DIP(fp, di_mode); | sb->st_mode = DIP(fp, di_mode); | ||||
sb->st_uid = DIP(fp, di_uid); | sb->st_uid = DIP(fp, di_uid); | ||||
sb->st_gid = DIP(fp, di_gid); | sb->st_gid = DIP(fp, di_gid); | ||||
sb->st_size = DIP(fp, di_size); | sb->st_size = DIP(fp, di_size); | ||||
Show All 33 Lines | again: | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
dp = (struct direct *)buf; | dp = (struct direct *)buf; | ||||
fp->f_seekp += dp->d_reclen; | fp->f_seekp += dp->d_reclen; | ||||
if (dp->d_ino == (ino_t)0) | if (dp->d_ino == (ino_t)0) | ||||
goto again; | goto again; | ||||
d->d_type = dp->d_type; | d->d_type = dp->d_type; | ||||
strcpy(d->d_name, dp->d_name); | strcpy(d->d_name, dp->d_name); | ||||
return (0); | |||||
} | |||||
static int | |||||
ufs_mount(const char *dev, const char *path, void **data) | |||||
{ | |||||
char *fs; | |||||
ufs_mnt_t *mnt; | |||||
errno = 0; | |||||
mnt = calloc(1, sizeof(*mnt)); | |||||
if (mnt == NULL) | |||||
return (errno); | |||||
imp: In the mount code, we test against -1, but errno is going to be a small positive number so I… | |||||
Done Inline Actionsmalloc/calloc, memalign etc do get errno set from sbr() - when heap is full, sbrk() is called. At this time, the mount() code is considering fo_mount() result 0 success and anything else fail. tsoome: malloc/calloc, memalign etc do get errno set from sbr() - when heap is full, sbrk() is called. | |||||
mnt->um_fd = -1; | |||||
mnt->um_dev = strdup(dev); | |||||
if (mnt->um_dev == NULL) | |||||
goto done; | |||||
Done Inline ActionsI'm not sure where strdup sets errno on failure. It should be in malloc, but that's the same code path as calloc so same question. imp: I'm not sure where strdup sets errno on failure. It should be in malloc, but that's the same… | |||||
if (asprintf(&fs, "%s%s", dev, path) < 0) | |||||
goto done; | |||||
Done Inline ActionsSame question here too. Sorry to be so tedious :) imp: Same question here too. Sorry to be so tedious :) | |||||
mnt->um_fd = open(fs, O_RDONLY); | |||||
Done Inline ActionsAt least for open I can fund where we set errno :) imp: At least for open I can fund where we set errno :) | |||||
free(fs); | |||||
if (mnt->um_fd == -1) | |||||
goto done; | |||||
STAILQ_INSERT_TAIL(&mnt_list, mnt, um_link); | |||||
done: | |||||
if (errno != 0) { | |||||
Done Inline ActionsYou should set errno = 0 at the top of this routine, otherwise you can get stale versions of errno and think there was an error when there wasn't. imp: You should set errno = 0 at the top of this routine, otherwise you can get stale versions of… | |||||
free(mnt->um_dev); | |||||
if (mnt->um_fd >= 0) | |||||
close(mnt->um_fd); | |||||
free(mnt); | |||||
} else { | |||||
*data = mnt; | |||||
} | |||||
return (errno); | |||||
} | |||||
static int | |||||
ufs_unmount(const char *dev, void *data) | |||||
{ | |||||
ufs_mnt_t *mnt = data; | |||||
STAILQ_REMOVE(&mnt_list, mnt, ufs_mnt, um_link); | |||||
free(mnt->um_dev); | |||||
close(mnt->um_fd); | |||||
free(mnt); | |||||
return (0); | return (0); | ||||
} | } |
In the mount code, we test against -1, but errno is going to be a small positive number so I think that's a mismatch.
Though I'm not sure where errno gets set for a calloc failure since znalloc doesn't seem to set it...