Changeset View
Changeset View
Standalone View
Standalone View
stand/libsa/dosfs.c
Show All 32 Lines | |||||
* also supports VFAT. | * also supports VFAT. | ||||
*/ | */ | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <stddef.h> | #include <stddef.h> | ||||
#include "stand.h" | #include "stand.h" | ||||
#include "disk.h" | |||||
#include "dosfs.h" | #include "dosfs.h" | ||||
typedef struct dos_mnt { | |||||
char *dos_dev; | |||||
DOS_FS *dos_fs; | |||||
int dos_fd; | |||||
STAILQ_ENTRY(dos_mnt) dos_link; | |||||
} dos_mnt_t; | |||||
typedef STAILQ_HEAD(dos_mnt_list, dos_mnt) dos_mnt_list_t; | |||||
static dos_mnt_list_t mnt_list = STAILQ_HEAD_INITIALIZER(mnt_list); | |||||
static int dos_open(const char *path, struct open_file *fd); | static int dos_open(const char *path, struct open_file *fd); | ||||
static int dos_close(struct open_file *fd); | static int dos_close(struct open_file *fd); | ||||
static int dos_read(struct open_file *fd, void *buf, size_t size, size_t *resid); | static int dos_read(struct open_file *fd, void *buf, size_t size, size_t *resid); | ||||
static off_t dos_seek(struct open_file *fd, off_t offset, int whence); | static off_t dos_seek(struct open_file *fd, off_t offset, int whence); | ||||
static int dos_stat(struct open_file *fd, struct stat *sb); | static int dos_stat(struct open_file *fd, struct stat *sb); | ||||
static int dos_readdir(struct open_file *fd, struct dirent *d); | static int dos_readdir(struct open_file *fd, struct dirent *d); | ||||
static int dos_mount(const char *dev, const char *path, void **data); | |||||
static int dos_unmount(const char *dev, void *data); | |||||
struct fs_ops dosfs_fsops = { | struct fs_ops dosfs_fsops = { | ||||
"dosfs", | .fs_name = "dosfs", | ||||
dos_open, | .fo_open = dos_open, | ||||
dos_close, | .fo_close = dos_close, | ||||
dos_read, | .fo_read = dos_read, | ||||
null_write, | .fo_write = null_write, | ||||
dos_seek, | .fo_seek = dos_seek, | ||||
dos_stat, | .fo_stat = dos_stat, | ||||
dos_readdir | .fo_readdir = dos_readdir, | ||||
.fo_mount = dos_mount, | |||||
.fo_unmount = dos_unmount | |||||
}; | }; | ||||
#define SECSIZ 512 /* sector size */ | #define SECSIZ 512 /* sector size */ | ||||
#define SSHIFT 9 /* SECSIZ shift */ | #define SSHIFT 9 /* SECSIZ shift */ | ||||
#define DEPSEC 16 /* directory entries per sector */ | #define DEPSEC 16 /* directory entries per sector */ | ||||
#define DSHIFT 4 /* DEPSEC shift */ | #define DSHIFT 4 /* DEPSEC shift */ | ||||
#define LOCLUS 2 /* lowest cluster number */ | #define LOCLUS 2 /* lowest cluster number */ | ||||
#define FATBLKSZ 0x20000 /* size of block in the FAT cache buffer */ | #define FATBLKSZ 0x20000 /* size of block in the FAT cache buffer */ | ||||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | dos_read_fatblk(DOS_FS *fs, struct open_file *fd, u_int blknum) | ||||
fs->fatbuf_blknum = blknum; | fs->fatbuf_blknum = blknum; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Mount DOS filesystem | * Mount DOS filesystem | ||||
*/ | */ | ||||
static int | static int | ||||
dos_mount(DOS_FS *fs, struct open_file *fd) | dos_mount_impl(DOS_FS *fs, struct open_file *fd) | ||||
{ | { | ||||
int err; | int err; | ||||
u_char *buf; | u_char *buf; | ||||
bzero(fs, sizeof(DOS_FS)); | |||||
fs->fd = fd; | fs->fd = fd; | ||||
if ((buf = malloc(secbyt(1))) == NULL) | if ((buf = malloc(secbyt(1))) == NULL) | ||||
return (errno); | return (errno); | ||||
if ((err = ioget(fs->fd, 0, buf, secbyt(1))) || | if ((err = ioget(fs->fd, 0, buf, secbyt(1))) || | ||||
(err = parsebs(fs, (DOS_BS *)buf))) { | (err = parsebs(fs, (DOS_BS *)buf))) { | ||||
free(buf); | free(buf); | ||||
return (err); | return (err); | ||||
Show All 14 Lines | if (fs->fatsz == 32) { | ||||
fs->root.clus[0] = fs->rdcl & 0xff; | fs->root.clus[0] = fs->rdcl & 0xff; | ||||
fs->root.clus[1] = (fs->rdcl >> 8) & 0xff; | fs->root.clus[1] = (fs->rdcl >> 8) & 0xff; | ||||
fs->root.dex.h_clus[0] = (fs->rdcl >> 16) & 0xff; | fs->root.dex.h_clus[0] = (fs->rdcl >> 16) & 0xff; | ||||
fs->root.dex.h_clus[1] = (fs->rdcl >> 24) & 0xff; | fs->root.dex.h_clus[1] = (fs->rdcl >> 24) & 0xff; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | |||||
dos_mount(const char *dev, const char *path, void **data) | |||||
{ | |||||
char *fs; | |||||
dos_mnt_t *mnt; | |||||
struct open_file *f; | |||||
DOS_FILE *df; | |||||
errno = 0; | |||||
mnt = calloc(1, sizeof(*mnt)); | |||||
if (mnt == NULL) | |||||
return (errno); | |||||
mnt->dos_fd = -1; | |||||
mnt->dos_dev = strdup(dev); | |||||
if (mnt->dos_dev == NULL) | |||||
goto done; | |||||
if (asprintf(&fs, "%s%s", dev, path) < 0) | |||||
goto done; | |||||
mnt->dos_fd = open(fs, O_RDONLY); | |||||
free(fs); | |||||
if (mnt->dos_fd == -1) | |||||
goto done; | |||||
f = fd2open_file(mnt->dos_fd); | |||||
if (strcmp(f->f_ops->fs_name, "dosfs") == 0) { | |||||
df = f->f_fsdata; | |||||
mnt->dos_fs = df->fs; | |||||
STAILQ_INSERT_TAIL(&mnt_list, mnt, dos_link); | |||||
} else { | |||||
errno = ENXIO; | |||||
} | |||||
done: | |||||
if (errno != 0) { | |||||
free(mnt->dos_dev); | |||||
if (mnt->dos_fd >= 0) | |||||
close(mnt->dos_fd); | |||||
free(mnt); | |||||
} else { | |||||
*data = mnt; | |||||
} | |||||
return (errno); | |||||
} | |||||
static int | |||||
dos_unmount(const char *dev __unused, void *data) | |||||
{ | |||||
dos_mnt_t *mnt = data; | |||||
STAILQ_REMOVE(&mnt_list, mnt, dos_mnt, dos_link); | |||||
free(mnt->dos_dev); | |||||
close(mnt->dos_fd); | |||||
free(mnt); | |||||
return (0); | |||||
} | |||||
/* | /* | ||||
* Unmount mounted filesystem | * Unmount mounted filesystem | ||||
*/ | */ | ||||
static int | static int | ||||
dos_unmount(DOS_FS *fs) | dos_unmount_impl(DOS_FS *fs) | ||||
{ | { | ||||
if (fs->links) | if (fs->links) | ||||
return (EBUSY); | return (EBUSY); | ||||
free(fs->fatbuf); | free(fs->fatbuf); | ||||
free(fs); | free(fs); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Open DOS file | * Open DOS file | ||||
*/ | */ | ||||
static int | static int | ||||
dos_open(const char *path, struct open_file *fd) | dos_open(const char *path, struct open_file *fd) | ||||
{ | { | ||||
DOS_DE *de; | DOS_DE *de; | ||||
DOS_FILE *f; | DOS_FILE *f; | ||||
DOS_FS *fs; | DOS_FS *fs; | ||||
dos_mnt_t *mnt; | |||||
const char *dev; | |||||
u_int size, clus; | u_int size, clus; | ||||
int err; | int err; | ||||
dev = disk_fmtdev(fd->f_devdata); | |||||
STAILQ_FOREACH(mnt, &mnt_list, dos_link) { | |||||
if (strcmp(dev, mnt->dos_dev) == 0) | |||||
break; | |||||
} | |||||
if (mnt == NULL) { | |||||
/* Allocate mount structure, associate with open */ | /* Allocate mount structure, associate with open */ | ||||
if ((fs = malloc(sizeof(DOS_FS))) == NULL) | if ((fs = malloc(sizeof(DOS_FS))) == NULL) | ||||
return (errno); | return (errno); | ||||
if ((err = dos_mount(fs, fd))) { | if ((err = dos_mount_impl(fs, fd))) { | ||||
free(fs); | free(fs); | ||||
return (err); | return (err); | ||||
} | } | ||||
} else { | |||||
fs = mnt->dos_fs; | |||||
} | |||||
if ((err = namede(fs, path, &de))) { | if ((err = namede(fs, path, &de))) { | ||||
dos_unmount(fs); | if (mnt == NULL) | ||||
dos_unmount_impl(fs); | |||||
return (err); | return (err); | ||||
} | } | ||||
clus = stclus(fs->fatsz, de); | clus = stclus(fs->fatsz, de); | ||||
size = cv4(de->size); | size = cv4(de->size); | ||||
if ((!(de->attr & FA_DIR) && (!clus != !size)) || | if ((!(de->attr & FA_DIR) && (!clus != !size)) || | ||||
((de->attr & FA_DIR) && size) || | ((de->attr & FA_DIR) && size) || | ||||
(clus && !okclus(fs, clus))) { | (clus && !okclus(fs, clus))) { | ||||
dos_unmount(fs); | if (mnt == NULL) | ||||
dos_unmount_impl(fs); | |||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
if ((f = malloc(sizeof(DOS_FILE))) == NULL) { | if ((f = calloc(1, sizeof(DOS_FILE))) == NULL) { | ||||
err = errno; | err = errno; | ||||
dos_unmount(fs); | if (mnt == NULL) | ||||
dos_unmount_impl(fs); | |||||
return (err); | return (err); | ||||
} | } | ||||
bzero(f, sizeof(DOS_FILE)); | |||||
f->fs = fs; | f->fs = fs; | ||||
fs->links++; | fs->links++; | ||||
f->de = *de; | f->de = *de; | ||||
fd->f_fsdata = (void *)f; | fd->f_fsdata = f; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Read from file | * Read from file | ||||
*/ | */ | ||||
static int | static int | ||||
dos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid) | dos_read(struct open_file *fd, void *buf, size_t nbyte, size_t *resid) | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
dos_close(struct open_file *fd) | dos_close(struct open_file *fd) | ||||
{ | { | ||||
DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; | DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; | ||||
DOS_FS *fs = f->fs; | DOS_FS *fs = f->fs; | ||||
f->fs->links--; | f->fs->links--; | ||||
free(f); | free(f); | ||||
dos_unmount(fs); | dos_unmount_impl(fs); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Return some stat information on a file. | * Return some stat information on a file. | ||||
*/ | */ | ||||
static int | static int | ||||
dos_stat(struct open_file *fd, struct stat *sb) | dos_stat(struct open_file *fd, struct stat *sb) | ||||
▲ Show 20 Lines • Show All 491 Lines • Show Last 20 Lines |