patch-1.3.60 linux/fs/fat/dir.c
Next file: linux/fs/fat/fatfs_syms.c
Previous file: linux/fs/fat/cache.c
Back to the patch index
Back to the overall index
- Lines: 282
- Date:
Wed Feb 7 09:39:27 1996
- Orig file:
v1.3.59/linux/fs/fat/dir.c
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v1.3.59/linux/fs/fat/dir.c linux/fs/fat/dir.c
@@ -0,0 +1,281 @@
+/*
+ * linux/fs/msdos/dir.c
+ * MS-DOS directory handling functions
+ *
+ * Written 1992,1993 by Werner Almesberger
+ *
+ * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
+ *
+ * VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner
+ */
+
+#include <linux/fs.h>
+#include <linux/msdos_fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/ioctl.h>
+
+#include <asm/segment.h>
+
+#include "msbuffer.h"
+#include "tables.h"
+
+
+#define PRINTK(X)
+
+static int fat_dir_read(struct inode * inode,struct file * filp, char * buf,int count)
+{
+ return -EISDIR;
+}
+
+struct file_operations fat_dir_operations = {
+ NULL, /* lseek - default */
+ fat_dir_read, /* read */
+ NULL, /* write - bad */
+ fat_readdir, /* readdir */
+ NULL, /* select - default */
+ fat_dir_ioctl, /* ioctl - default */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ file_fsync /* fsync */
+};
+
+
+int fat_dir_ioctl(struct inode * inode, struct file * filp,
+ unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+#if 0
+ /*
+ * We want to provide an interface for Samba to be able
+ * to get the short filename for a given long filename.
+ * We should be able to accomplish by modifying fat_readdir
+ * slightly.
+ */
+ case VFAT_LONGNAME_TO_SHORT:
+#endif
+ default:
+ return -EINVAL;
+ }
+}
+
+int fat_readdir(
+ struct inode *inode,
+ struct file *filp,
+ void *dirent,
+ filldir_t filldir)
+{
+ struct super_block *sb = inode->i_sb;
+ int ino,i,i2,last;
+ char c;
+ struct buffer_head *bh;
+ struct msdos_dir_entry *de;
+ unsigned long oldpos = filp->f_pos;
+ int is_long;
+ char longname[256];
+ unsigned char long_len = 0; /* Make compiler warning go away */
+ unsigned char alias_checksum = 0; /* Make compiler warning go away */
+
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+/* Fake . and .. for the root directory. */
+ if (inode->i_ino == MSDOS_ROOT_INO) {
+ while (oldpos < 2) {
+ if (filldir(dirent, "..", oldpos+1, oldpos, MSDOS_ROOT_INO) < 0)
+ return 0;
+ oldpos++;
+ filp->f_pos++;
+ }
+ if (oldpos == 2)
+ filp->f_pos = 0;
+ }
+ if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1))
+ return -ENOENT;
+
+ bh = NULL;
+ longname[0] = '\0';
+ is_long = 0;
+ ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
+ while (ino > -1) {
+ /* Should we warn about finding extended entries on fs
+ * mounted non-vfat ? Deleting or renaming files will cause
+ * corruption, as extended entries are not updated.
+ */
+ if (!MSDOS_SB(sb)->vfat &&
+ !MSDOS_SB(sb)->umsdos && /* umsdos is safe for us */
+ !IS_RDONLY(inode) &&
+ (de->attr == ATTR_EXT) &&
+ !MSDOS_SB(sb)->quiet) {
+ printk("MSDOS-fs warning: vfat directory entry found on fs mounted non-vfat (device %s)\n",
+ kdevname(sb->s_dev));
+ }
+
+ /* Check for long filename entry */
+ if (MSDOS_SB(sb)->vfat && (de->name[0] == (__s8) DELETED_FLAG)) {
+ is_long = 0;
+ oldpos = filp->f_pos;
+ } else if (MSDOS_SB(sb)->vfat && de->attr == ATTR_EXT) {
+ int get_new_entry;
+ struct msdos_dir_slot *ds;
+ unsigned char page, pg_off, ascii;
+ unsigned char *uni_page;
+ unsigned char offset;
+ unsigned char id;
+ unsigned char slot;
+ unsigned char slots = 0;
+ int i;
+
+ offset = 0;
+ ds = (struct msdos_dir_slot *) de;
+ id = ds->id;
+ if (id & 0x40) {
+ slots = id & ~0x40;
+ is_long = 1;
+ alias_checksum = ds->alias_checksum;
+ }
+
+ get_new_entry = 1;
+ slot = slots;
+ while (slot > 0) {
+ PRINTK(("1. get_new_entry: %d\n", get_new_entry));
+ if (ds->attr != ATTR_EXT) {
+ is_long = 0;
+ get_new_entry = 0;
+ break;
+ }
+ if ((ds->id & ~0x40) != slot) {
+ is_long = 0;
+ break;
+ }
+ if (ds->alias_checksum != alias_checksum) {
+ is_long = 0;
+ break;
+ }
+ slot--;
+ offset = slot * 13;
+ PRINTK(("2. get_new_entry: %d\n", get_new_entry));
+ for (i = 0; i < 10; i += 2) {
+ pg_off = ds->name0_4[i];
+ page = ds->name0_4[i+1];
+ if (pg_off == 0 && page == 0) {
+ goto found_end;
+ }
+ uni_page = fat_uni2asc_pg[page];
+ ascii = uni_page[pg_off];
+ longname[offset++] = ascii ? ascii : '?';
+ }
+ for (i = 0; i < 12; i += 2) {
+ pg_off = ds->name5_10[i];
+ page = ds->name5_10[i+1];
+ if (pg_off == 0 && page == 0) {
+ goto found_end;
+ }
+ uni_page = fat_uni2asc_pg[page];
+ ascii = uni_page[pg_off];
+ longname[offset++] = ascii ? ascii : '?';
+ }
+ for (i = 0; i < 4; i += 2) {
+ pg_off = ds->name11_12[i];
+ page = ds->name11_12[i+1];
+ if (pg_off == 0 && page == 0) {
+ goto found_end;
+ }
+ uni_page = fat_uni2asc_pg[page];
+ ascii = uni_page[pg_off];
+ longname[offset++] = ascii ? ascii : '?';
+ }
+ found_end:
+ PRINTK(("3. get_new_entry: %d\n", get_new_entry));
+ if (ds->id & 0x40) {
+ longname[offset] = '\0';
+ long_len = offset;
+ }
+ if (slot > 0) {
+ ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
+ PRINTK(("4. get_new_entry: %d\n", get_new_entry));
+ if (ino == -1) {
+ is_long = 0;
+ get_new_entry = 0;
+ break;
+ }
+ ds = (struct msdos_dir_slot *) de;
+ }
+ PRINTK(("5. get_new_entry: %d\n", get_new_entry));
+ }
+ PRINTK(("Long filename: %s, get_new_entry: %d\n", longname, get_new_entry));
+ } else if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) {
+ char bufname[13];
+ char *ptname = bufname;
+ int dotoffset = 0;
+
+ if (is_long) {
+ unsigned char sum;
+
+ for (sum = i = 0; i < 11; i++) {
+ sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
+ }
+
+ if (sum != alias_checksum) {
+ PRINTK(("Checksums don't match %d != %d\n", sum, alias_checksum));
+ is_long = 0;
+ }
+ }
+
+ if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->dotsOK) {
+ bufname[0] = '.';
+ dotoffset = 1;
+ ptname = bufname+1;
+ }
+ for (i = last = 0; i < 8; i++) {
+ if (!(c = de->name[i])) break;
+ if (c >= 'A' && c <= 'Z') c += 32;
+ /* see namei.c, msdos_format_name */
+ if (c == 0x05) c = 0xE5;
+ if (c != ' ')
+ last = i+1;
+ ptname[i] = c;
+ }
+ i = last;
+ ptname[i] = '.';
+ i++;
+ for (i2 = 0; i2 < 3; i2++) {
+ if (!(c = de->ext[i2])) break;
+ if (c >= 'A' && c <= 'Z') c += 32;
+ if (c != ' ')
+ last = i+1;
+ ptname[i] = c;
+ i++;
+ }
+ if ((i = last) != 0) {
+ if (!strcmp(de->name,MSDOS_DOT))
+ ino = inode->i_ino;
+ else if (!strcmp(de->name,MSDOS_DOTDOT))
+ ino = fat_parent_ino(inode,0);
+
+ if (!is_long) {
+ if (filldir(dirent, bufname, i+dotoffset, oldpos, ino) < 0) {
+ filp->f_pos = oldpos;
+ break;
+ }
+ } else {
+ if (filldir(dirent, longname, long_len, oldpos, ino) < 0) {
+ filp->f_pos = oldpos;
+ break;
+ }
+ }
+ oldpos = filp->f_pos;
+ }
+ is_long = 0;
+ } else {
+ is_long = 0;
+ oldpos = filp->f_pos;
+ }
+ ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
+ }
+ if (bh) brelse(bh);
+ return 0;
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this