summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2001-12-11 00:03:10 +0000
committerjhb <jhb@FreeBSD.org>2001-12-11 00:03:10 +0000
commit15b4e20f28ce71e958a7b22e3b4b92c0b3df727a (patch)
treef4894cbaa0343317cead90f53a678607c5c90853
parentdd0efc9785a26030b50b39b329d23d824a06b794 (diff)
downloadFreeBSD-src-15b4e20f28ce71e958a7b22e3b4b92c0b3df727a.zip
FreeBSD-src-15b4e20f28ce71e958a7b22e3b4b92c0b3df727a.tar.gz
Add support for overwriting the existing contents of a file to the UFS
driver in libstand. This specifically does not expand or truncate files since the filesystem may be dirty or inconsistent. PR: kern/32389 Submitted by: Jonathan Mini <mini@haikugeek.com> Sponsored by: ClickArray, Inc.
-rw-r--r--lib/libstand/ufs.c123
1 files changed, 119 insertions, 4 deletions
diff --git a/lib/libstand/ufs.c b/lib/libstand/ufs.c
index c501fe9..35af957 100644
--- a/lib/libstand/ufs.c
+++ b/lib/libstand/ufs.c
@@ -82,6 +82,7 @@ __FBSDID("$FreeBSD$");
#endif
static int ufs_open(const char *path, struct open_file *f);
+static int ufs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
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 off_t ufs_seek(struct open_file *f, off_t offset, int where);
@@ -93,7 +94,7 @@ struct fs_ops ufs_fsops = {
ufs_open,
ufs_close,
ufs_read,
- null_write,
+ ufs_write,
ufs_seek,
ufs_stat,
ufs_readdir
@@ -122,6 +123,7 @@ struct file {
static int read_inode(ino_t, struct open_file *);
static int block_map(struct open_file *, daddr_t, daddr_t *);
static int buf_read_file(struct open_file *, char **, size_t *);
+static int buf_write_file(struct open_file *, char *, size_t *);
static int search_directory(char *, struct open_file *, ino_t *);
#ifdef COMPAT_UFS
static void ffs_oldfscompat(struct fs *);
@@ -288,6 +290,82 @@ block_map(f, file_block, disk_block_p)
}
/*
+ * Write a portion of a file from an internal buffer.
+ */
+static int
+buf_write_file(f, buf_p, size_p)
+ struct open_file *f;
+ char *buf_p;
+ size_t *size_p; /* out */
+{
+ register struct file *fp = (struct file *)f->f_fsdata;
+ register struct fs *fs = fp->f_fs;
+ long off;
+ register daddr_t file_block;
+ daddr_t disk_block;
+ size_t block_size;
+ int rc;
+
+ /*
+ * Calculate the starting block address and offset.
+ */
+ off = blkoff(fs, fp->f_seekp);
+ file_block = lblkno(fs, fp->f_seekp);
+ block_size = dblksize(fs, &fp->f_di, file_block);
+
+ rc = block_map(f, file_block, &disk_block);
+ if (rc)
+ return (rc);
+
+ if (disk_block == 0)
+ return (EFBIG); /* Because we can't allocate space on the drive */
+
+ /*
+ * Truncate buffer at end of file, and at the end of
+ * this block.
+ */
+ if (*size_p > fp->f_di.di_size - fp->f_seekp)
+ *size_p = fp->f_di.di_size - fp->f_seekp;
+ if (*size_p > block_size - off)
+ *size_p = block_size - off;
+
+ /*
+ * If we don't entirely occlude the block and it's not
+ * in memory already, read it in first.
+ */
+ if (((off > 0) || (*size_p + off < block_size)) &&
+ (file_block != fp->f_buf_blkno)) {
+
+ if (fp->f_buf == (char *)0)
+ fp->f_buf = malloc(fs->fs_bsize);
+
+ twiddle();
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
+ fsbtodb(fs, disk_block),
+ block_size, fp->f_buf, &fp->f_buf_size);
+ if (rc)
+ return (rc);
+
+ fp->f_buf_blkno = file_block;
+ }
+
+ /*
+ * Copy the user data into the cached block.
+ */
+ bcopy(buf_p,fp->f_buf + off,*size_p);
+
+ /*
+ * Write the block out to storage.
+ */
+
+ twiddle();
+ rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
+ fsbtodb(fs, disk_block),
+ block_size, fp->f_buf, &fp->f_buf_size);
+ return (rc);
+}
+
+/*
* Read a portion of a file into an internal buffer. Return
* the location in the buffer and the amount in the buffer.
*/
@@ -310,13 +388,13 @@ buf_read_file(f, buf_p, size_p)
block_size = dblksize(fs, &fp->f_di, file_block);
if (file_block != fp->f_buf_blkno) {
+ if (fp->f_buf == (char *)0)
+ fp->f_buf = malloc(fs->fs_bsize);
+
rc = block_map(f, file_block, &disk_block);
if (rc)
return (rc);
- if (fp->f_buf == (char *)0)
- fp->f_buf = malloc(fs->fs_bsize);
-
if (disk_block == 0) {
bzero(fp->f_buf, block_size);
fp->f_buf_size = block_size;
@@ -658,6 +736,43 @@ ufs_read(f, start, size, resid)
return (rc);
}
+/*
+ * Write to a portion of an already allocated file.
+ * Cross block boundaries when necessary. Can not
+ * extend the file.
+ */
+static int
+ufs_write(f, start, size, resid)
+ struct open_file *f;
+ void *start;
+ size_t size;
+ size_t *resid; /* out */
+{
+ register struct file *fp = (struct file *)f->f_fsdata;
+ size_t csize;
+ int rc = 0;
+ register char *addr = start;
+
+ csize = size;
+ while ((size != 0) && (csize != 0)) {
+ if (fp->f_seekp >= fp->f_di.di_size)
+ break;
+
+ if (csize >= 512) csize = 512; /* XXX */
+
+ rc = buf_write_file(f, addr, &csize);
+ if (rc)
+ break;
+
+ fp->f_seekp += csize;
+ addr += csize;
+ size -= csize;
+ }
+ if (resid)
+ *resid = size;
+ return (rc);
+}
+
static off_t
ufs_seek(f, offset, where)
struct open_file *f;
OpenPOWER on IntegriCloud