summaryrefslogtreecommitdiffstats
path: root/fs/hpfs/file.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-17 14:08:29 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-17 14:08:29 +0000
commit57d569635c05dc4ea9b9f1f8dcec69b9ddc989b2 (patch)
tree1f703abf7d95dcd50ee52da3b96eb1b4b2b4ea53 /fs/hpfs/file.c
parent59223edaa18759982db0a8aced0e77457d10c68e (diff)
The rest of 2.3.6.
Diffstat (limited to 'fs/hpfs/file.c')
-rw-r--r--fs/hpfs/file.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
new file mode 100644
index 000000000..7cea8dcdc
--- /dev/null
+++ b/fs/hpfs/file.c
@@ -0,0 +1,195 @@
+/*
+ * linux/fs/hpfs/file.c
+ *
+ * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
+ *
+ * file VFS functions
+ */
+
+#include <linux/string.h>
+#include "hpfs_fn.h"
+
+int hpfs_open(struct inode *i, struct file *f)
+{
+ hpfs_lock_inode(i);
+ hpfs_unlock_inode(i); /* make sure nobody is deleting the file */
+ if (!i->i_nlink) return -ENOENT;
+ return 0;
+}
+
+int hpfs_file_release(struct inode *inode, struct file *file)
+{
+ hpfs_write_if_changed(inode);
+ return 0;
+}
+
+int hpfs_file_fsync(struct file *file, struct dentry *dentry)
+{
+ /*return file_fsync(file, dentry);*/
+ return 0; /* Don't fsync :-) */
+}
+
+/*
+ * generic_file_read often calls bmap with non-existing sector,
+ * so we must ignore such errors.
+ */
+
+secno hpfs_bmap(struct inode *inode, unsigned file_secno)
+{
+ unsigned n, disk_secno;
+ struct fnode *fnode;
+ struct buffer_head *bh;
+ if (((inode->i_size + 511) >> 9) <= file_secno) return 0;
+ n = file_secno - inode->i_hpfs_file_sec;
+ if (n < inode->i_hpfs_n_secs) return inode->i_hpfs_disk_sec + n;
+ if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0;
+ disk_secno = hpfs_bplus_lookup(inode->i_sb, inode, &fnode->btree, file_secno, bh);
+ if (disk_secno == -1) return 0;
+ if (hpfs_chk_sectors(inode->i_sb, disk_secno, 1, "bmap")) return 0;
+ return disk_secno;
+}
+
+void hpfs_truncate(struct inode *i)
+{
+ if (IS_IMMUTABLE(i)) return /*-EPERM*/;
+ i->i_hpfs_n_secs = 0;
+ hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
+ i->i_blocks = 1 + ((i->i_size + 511) >> 9);
+ hpfs_write_inode(i);
+}
+
+ssize_t hpfs_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ int i,j;
+ int a = generic_file_read(filp, buf, count, ppos);
+ if (inode->i_hpfs_conv != CONV_TEXT || a < 0) {
+ return a;
+ }
+ for (i = 0, j = 0; i < a; i++) {
+ char c;
+ int error;
+ if ((error = get_user(c, buf + i))) return error;
+ if (c != '\r') {
+ if (i != j) put_user(c, buf + j);
+ j++;
+ }
+ }
+ return j;
+}
+
+ssize_t hpfs_file_write(struct file *filp, const char *buf, size_t count,
+ loff_t *ppos)
+{
+ struct inode *i = filp->f_dentry->d_inode;
+ int carry, error = 0;
+ const char *start = buf;
+ if (!i) return -EINVAL;
+ if (!S_ISREG(i->i_mode)) return -EINVAL;
+ if (IS_IMMUTABLE(i)) return -EPERM;
+ if (filp->f_flags & O_APPEND) *ppos = i->i_size;
+ if (count <= 0) return 0;
+ if ((unsigned)(*ppos+count) >= 0x80000000U || (unsigned)count >= 0x80000000U) return -EFBIG;
+ carry = 0;
+ while (count || carry) {
+ int ii, add = 0;
+ secno sec = 0; /* Go away, uninitialized variable warning */
+ int offset, size, written;
+ char ch;
+ struct buffer_head *bh;
+ char *data;
+ offset = *ppos & 0x1ff;
+ size = count > 0x200 - offset ? 0x200 - offset : count;
+ if ((*ppos >> 9) < ((i->i_size + 0x1ff) >> 9)) {
+ i->i_hpfs_n_secs = 0;
+ if (!(sec = hpfs_bmap(i, *ppos >> 9))) {
+ hpfs_error(i->i_sb, "bmap failed, file %08x, fsec %08x",
+ i->i_ino, *ppos >> 9);
+ error =- EFSERROR;
+ break;
+ }
+ } else for (ii = (i->i_size + 0x1ff) >> 9, add = 1; ii <= *ppos >> 9; ii++) {
+ if ((sec = hpfs_add_sector_to_btree(i->i_sb, i->i_ino, 1, ii)) == -1) {
+ hpfs_truncate(i);
+ return -ENOSPC;
+ }
+ if (*ppos != i->i_size)
+ if ((data = hpfs_get_sector(i->i_sb, sec, &bh))) {
+ memset(data, 0, 512);
+ mark_buffer_dirty(bh, 0);
+ brelse(bh);
+ }
+ i->i_size = 0x200 * ii + 1;
+ i->i_blocks++;
+ /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
+ if (i->i_sb->s_hpfs_chk >= 2) {
+ secno bsec;
+ bsec = hpfs_bmap(i, ii);
+ if (sec != bsec) {
+ hpfs_error(i->i_sb, "sec == %08x, bmap returns %08x", sec, bsec);
+ error = -EFSERROR;
+ break;
+ }
+ }
+ PRINTK(("file_write: added %08x\n", sec));
+ }
+ if (!sec || sec == 15) {
+ hpfs_error(i->i_sb, "bmap returned empty sector");
+ error = -EFSERROR;
+ break;
+ }
+ if (i->i_sb->s_hpfs_chk)
+ if (hpfs_chk_sectors(i->i_sb, sec, 1, "data")) {
+ error = -EFSERROR;
+ break;
+ }
+ if ((!offset && size == 0x200) || add)
+ data = hpfs_get_sector(i->i_sb, sec, &bh);
+ else data = hpfs_map_sector(i->i_sb, sec, &bh, 0);
+ if (!data) {
+ error = -EIO;
+ break;
+ }
+ if (i->i_hpfs_conv != CONV_TEXT) {
+ memcpy_fromfs(data + offset, buf, written = size);
+ buf += size;
+ } else {
+ int left;
+ char *to;
+ /* LF->CR/LF conversion, stolen from fat fs */
+ written = left = 0x200 - offset;
+ to = (char *) bh->b_data + (*ppos & 0x1ff);
+ if (carry) {
+ *to++ = '\n';
+ left--;
+ carry = 0;
+ }
+ for (size = 0; size < count && left; size++) {
+ if ((error = get_user(ch, buf++))) break;
+ if (ch == '\n') {
+ *to++ = '\r';
+ left--;
+ }
+ if (!left) carry = 1;
+ else {
+ *to++ = ch;
+ left--;
+ }
+ }
+ written -= left;
+ }
+ update_vm_cache(i, *ppos, bh->b_data + (*ppos & 0x1ff), written);
+ *ppos += written;
+ if (*ppos > i->i_size) {
+ i->i_size = *ppos;
+ /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
+ }
+ mark_buffer_dirty(bh, 0);
+ brelse(bh);
+ count -= size;
+ }
+ if (start == buf) return error;
+ i->i_mtime = CURRENT_TIME;
+ /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
+ return buf - start;
+}