/* * Compare two msdos names. If either of the names are invalid, * we fall back to doing the standard name comparison. */ static int msdos_cmp(const struct dentry *parent, const struct dentry *dentry, unsigned int len, const char *str, const struct qstr *name) { struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options; unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; int error; error = msdos_format_name(name->name, name->len, a_msdos_name, options); if (error) goto old_compare; error = msdos_format_name(str, len, b_msdos_name, options); if (error) goto old_compare; error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME); out: return error; old_compare: error = 1; if (name->len == len) error = memcmp(name->name, str, len); goto out; }
/* * Preallocate space for a file. This implements fat's fallocate file * operation, which gets called from sys_fallocate system call. User * space requests len bytes at offset. If FALLOC_FL_KEEP_SIZE is set * we just allocate clusters without zeroing them out. Otherwise we * allocate and zero out clusters via an expanding truncate. */ static long fat_fallocate(struct file *file, int mode, loff_t offset, loff_t len) { int nr_cluster; /* Number of clusters to be allocated */ loff_t mm_bytes; /* Number of bytes to be allocated for file */ loff_t ondisksize; /* block aligned on-disk size in bytes*/ struct inode *inode = file->f_mapping->host; struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); int err = 0; /* No support for hole punch or other fallocate flags. */ if (mode & ~FALLOC_FL_KEEP_SIZE) return -EOPNOTSUPP; /* No support for dir */ if (!S_ISREG(inode->i_mode)) return -EOPNOTSUPP; inode_lock(inode); if (mode & FALLOC_FL_KEEP_SIZE) { ondisksize = inode->i_blocks << 9; if ((offset + len) <= ondisksize) goto error; /* First compute the number of clusters to be allocated */ mm_bytes = offset + len - ondisksize; nr_cluster = (mm_bytes + (sbi->cluster_size - 1)) >> sbi->cluster_bits; /* Start the allocation.We are not zeroing out the clusters */ while (nr_cluster-- > 0) { err = fat_add_cluster(inode); if (err) goto error; } } else {
static int msdos_add_entry(struct inode *dir, const unsigned char *name, int is_dir, int is_hid, int cluster, struct timespec *ts, struct fat_slot_info *sinfo) { struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb); struct msdos_dir_entry de; __le16 time, date; int err; memcpy(de.name, name, MSDOS_NAME); de.attr = is_dir ? ATTR_DIR : ATTR_ARCH; if (is_hid) de.attr |= ATTR_HIDDEN; de.lcase = 0; fat_time_unix2fat(sbi, ts, &time, &date, NULL); de.cdate = de.adate = 0; de.ctime = 0; de.ctime_cs = 0; de.time = time; de.date = date; de.start = cpu_to_le16(cluster); de.starthi = cpu_to_le16(cluster >> 16); de.size = 0; err = fat_add_entries(dir, &de, 1, sinfo); if (err) return err; dir->i_ctime = dir->i_mtime = *ts; if (IS_DIRSYNC(dir)) (void)fat_sync_inode(dir); else mark_inode_dirty(dir); return 0; }
/* Read the super block of an Extended MS-DOS FS. */ struct super_block *UMSDOS_read_super( struct super_block *s, void *data, int silent) { /* #Specification: mount / options Umsdos run on top of msdos. Currently, it supports no mount option, but happily pass all option received to the msdos driver. I am not sure if all msdos mount option make sense with Umsdos. Here are at least those who are useful. uid= gid= These options affect the operation of umsdos in directories which do not have an EMD file. They behave like normal msdos directory, with all limitation of msdos. */ struct super_block *sb; MOD_INC_USE_COUNT; sb = msdos_read_super(s,data,silent); printk ("UMSDOS Beta 0.6 (compatibility level %d.%d, fast msdos)\n" ,UMSDOS_VERSION,UMSDOS_RELEASE); if (sb != NULL){ MSDOS_SB(sb)->options.dotsOK = 0; /* disable hidden==dotfile */ sb->s_op = &umsdos_sops; PRINTK (("umsdos_read_super %p\n",sb->s_mounted)); umsdos_setup_dir_inode (sb->s_mounted); PRINTK (("End umsdos_read_super\n")); if (s == super_blocks){ /* #Specification: pseudo root / mount When a umsdos fs is mounted, a special handling is done if it is the root partition. We check for the presence of the file /linux/etc/init or /linux/etc/rc or /linux/sbin/init. If one is there, we do a chroot("/linux"). We check both because (see init/main.c) the kernel try to exec init at different place and if it fails it tries /bin/sh /etc/rc. To be consistent with init/main.c, many more test would have to be done to locate init. Any complain ? The chroot is done manually in init/main.c but the info (the inode) is located at mount time and store in a global variable (pseudo_root) which is used at different place in the umsdos driver. There is no need to store this variable elsewhere because it will always be one, not one per mount. This feature allows the installation of a linux system within a DOS system in a subdirectory. A user may install its linux stuff in c:\linux avoiding any clash with existing DOS file and subdirectory. When linux boots, it hides this fact, showing a normal root directory with /etc /bin /tmp ... The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h in the macro UMSDOS_PSDROOT_NAME. */ struct inode *pseudo; Printk (("Mounting root\n")); if (umsdos_real_lookup (sb->s_mounted,UMSDOS_PSDROOT_NAME ,UMSDOS_PSDROOT_LEN,&pseudo)==0 && S_ISDIR(pseudo->i_mode)){ struct inode *etc = NULL; struct inode *sbin = NULL; int pseudo_ok = 0; Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME)); if (umsdos_real_lookup (pseudo,"etc",3,&etc)==0 && S_ISDIR(etc->i_mode)){ struct inode *init = NULL; struct inode *rc = NULL; Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME)); if ((umsdos_real_lookup (etc,"init",4,&init)==0 && S_ISREG(init->i_mode)) || (umsdos_real_lookup (etc,"rc",2,&rc)==0 && S_ISREG(rc->i_mode))){ pseudo_ok = 1; } iput (init); iput (rc); } if (!pseudo_ok && umsdos_real_lookup (pseudo,"sbin",4,&sbin)==0 && S_ISDIR(sbin->i_mode)){ struct inode *init = NULL; Printk (("/%s/sbin is there\n",UMSDOS_PSDROOT_NAME)); if (umsdos_real_lookup (sbin,"init",4,&init)==0 && S_ISREG(init->i_mode)){ pseudo_ok = 1; } iput (init); } if (pseudo_ok){ umsdos_setup_dir_inode (pseudo); Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME)); pseudo_root = pseudo; pseudo->i_count++; pseudo = NULL; } iput (sbin); iput (etc); } iput (pseudo); } } else { MOD_DEC_USE_COUNT; } return sb; }
// by rzq: for supporting /proc file system static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) { struct fat_sb_info *sbi = MSDOS_SB(mnt->mnt_sb); struct fat_mount_options *opts = &sbi->options; int isvfat = opts->isvfat; printk (KERN_INFO "myfat: fat_show_options\n"); if (opts->fs_uid != 0) seq_printf(m, ",uid=%u", opts->fs_uid); if (opts->fs_gid != 0) seq_printf(m, ",gid=%u", opts->fs_gid); seq_printf(m, ",fmask=%04o", opts->fs_fmask); seq_printf(m, ",dmask=%04o", opts->fs_dmask); if (opts->allow_utime) seq_printf(m, ",allow_utime=%04o", opts->allow_utime); if (sbi->nls_disk) seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); if (isvfat) { if (sbi->nls_io) seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); switch (opts->shortname) { case VFAT_SFN_DISPLAY_WIN95 | VFAT_SFN_CREATE_WIN95: seq_puts(m, ",shortname=win95"); break; case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WINNT: seq_puts(m, ",shortname=winnt"); break; case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WIN95: seq_puts(m, ",shortname=mixed"); break; case VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95: seq_puts(m, ",shortname=lower"); break; default: seq_puts(m, ",shortname=unknown"); break; } } if (opts->name_check != 'n') seq_printf(m, ",check=%c", opts->name_check); if (opts->usefree) seq_puts(m, ",usefree"); if (opts->quiet) seq_puts(m, ",quiet"); if (opts->showexec) seq_puts(m, ",showexec"); if (opts->sys_immutable) seq_puts(m, ",sys_immutable"); if (!isvfat) { if (opts->dotsOK) seq_puts(m, ",dotsOK=yes"); if (opts->nocase) seq_puts(m, ",nocase"); } else { if (opts->utf8) seq_puts(m, ",utf8"); if (opts->unicode_xlate) seq_puts(m, ",uni_xlate"); if (!opts->numtail) seq_puts(m, ",nonumtail"); if (opts->rodir) seq_puts(m, ",rodir"); } if (opts->flush) seq_puts(m, ",flush"); if (opts->tz_utc) seq_puts(m, ",tz=UTC"); if (opts->errors == FAT_ERRORS_CONT) seq_puts(m, ",errors=continue"); else if (opts->errors == FAT_ERRORS_PANIC) seq_puts(m, ",errors=panic"); else seq_puts(m, ",errors=remount-ro"); return 0; }
int isNodeContinuous(struct inode *inode) { struct fat_entry fatent; int dclus = 0; int nr = 0; struct msdos_inode_info * msinode= NULL; struct super_block *sb = NULL; struct msdos_sb_info *sbi = NULL; struct msdos_dir_entry *uninitialized_var(de); /*if (NULL != file && NULL != file->f_mapping) { inode = file->f_mapping->host; } else { printk(KERN_INFO "file or file->f_mapping is null, file:%x\n", (unsigned int)file); return 0; }*/ if (NULL != inode) { msinode= MSDOS_I(inode); sb = inode->i_sb; } else { printk(KERN_INFO "inode is null\n"); return 0; } //printk(KERN_INFO "3, inode:%x\n", (unsigned int)inode); if (NULL == msinode) { printk(KERN_INFO "msinode is null\n"); return 0; } if (NULL != sb) { sbi = MSDOS_SB(sb); } if (NULL == sbi) { printk(KERN_INFO "sbi is null\n"); return 0; } if (msinode->i_start < FAT_START_ENT || msinode->i_start > sbi->max_cluster) { printk(KERN_INFO "!!!start cluster is not correct\n"); return 1; } lock_fat2(sbi); dclus = msinode->i_start; fatent_init(&fatent); while (dclus < FAT_ENT_EOF) { //printk(KERN_INFO "%d ", dclus); nr = fat_ent_read(inode, &fatent, dclus); if (FAT_ENT_EOF != nr && nr != (dclus + 1)) { fatent_brelse(&fatent); unlock_fat2(sbi); printk(KERN_INFO "file is not contiguous\n"); return 0; } dclus = nr; } fatent_brelse(&fatent); unlock_fat2(sbi); return 1; }
int fat_find_first_free_clusters(struct super_block *sb, u_int32_t MinimumLcn, u_int32_t MinimumSize, u_int32_t *BeginLcn, u_int32_t *EndLcn) { struct msdos_sb_info *sbi = MSDOS_SB(sb); struct fatent_operations *ops = sbi->fatent_ops; struct fat_entry fatent; unsigned long reada_blocks, reada_mask, cur_block; int err = 0; u_int32_t start = 0; *BeginLcn = 0; *EndLcn = 0; if (MinimumLcn >= sbi->max_cluster) { printk(KERN_INFO "fat_find_first_free_clusters minimum lcn is out of side\n"); return 0; } lock_fat2(sbi); if (sbi->free_clusters != -1 && sbi->free_clus_valid && sbi->free_clusters < MinimumSize) { printk(KERN_INFO "fat_find_first_free_clusters failed, free_clusters:%d, free_clus_valid:%d\n", sbi->free_clusters, sbi->free_clus_valid); goto out2; } reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits; reada_mask = reada_blocks - 1; cur_block = 0; fatent_init(&fatent); fatent_set_entry(&fatent, MinimumLcn); while (fatent.entry < sbi->max_cluster) { /* readahead of fat blocks */ /*if ((cur_block & reada_mask) == 0) { unsigned long rest = sbi->fat_length - cur_block; fat_ent_reada2(sb, &fatent, min(reada_blocks, rest)); } cur_block++;*/ fatent_set_entry(&fatent, fatent.entry); err = fat_ent_read_block2(sb, &fatent); if (err) { printk(KERN_INFO "fat_find_first_free_clusters fat_ent_read_block2 failed\n"); goto out1; } do { if (ops->ent_get(&fatent) == FAT_ENT_FREE) { if (start == 0) { start = fatent.entry; } if (fatent.entry >= sbi->max_cluster) { if ((fatent.entry - start) >= MinimumSize) { //printk(KERN_INFO "fat_find_first_free_clusters OK\n"); *BeginLcn = start; *EndLcn = fatent.entry; goto out1; } } } else { if (0 != start) { if ((fatent.entry - start) >= MinimumSize) { *BeginLcn = start; *EndLcn = fatent.entry; goto out1; } } start = 0; } } while (fat_ent_next2(sbi, &fatent)); if (fatent.entry >= sbi->max_cluster) { if (0 != start) { if ((fatent.entry - start) >= MinimumSize) { *BeginLcn = start; *EndLcn = fatent.entry; } } //printk(KERN_INFO "fat_find_first_free_clusters end...\n"); } } out1: //printk(KERN_INFO "fat_find_first_free_clusters out1:%d, val:%d, *BeginLcn:%d, sbi->fat_length:%ld, free_clusters:%d\n", // fatent.entry, ops->ent_get(&fatent), *BeginLcn, sbi->fat_length, sbi->free_clusters); fatent_brelse(&fatent); out2: unlock_fat2(sbi); return *BeginLcn; }
void fat_brelse (struct super_block *sb, struct buffer_head *bh) { if (bh) MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh); }
/* Free all clusters after the skip'th cluster. */ static int fat_free(struct inode *inode, int skip) { struct super_block *sb = inode->i_sb; int err, wait, free_start, i_start, i_logstart; if (MSDOS_I(inode)->i_start == 0) return 0; fat_cache_inval_inode(inode); wait = IS_DIRSYNC(inode); i_start = free_start = MSDOS_I(inode)->i_start; i_logstart = MSDOS_I(inode)->i_logstart; /* First, we write the new file size. */ if (!skip) { MSDOS_I(inode)->i_start = 0; MSDOS_I(inode)->i_logstart = 0; } MSDOS_I(inode)->i_attrs |= ATTR_ARCH; inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; if (wait) { err = fat_sync_inode(inode); if (err) { MSDOS_I(inode)->i_start = i_start; MSDOS_I(inode)->i_logstart = i_logstart; return err; } } else mark_inode_dirty(inode); /* Write a new EOF, and get the remaining cluster chain for freeing. */ if (skip) { struct fat_entry fatent; int ret, fclus, dclus; ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus); if (ret < 0) return ret; else if (ret == FAT_ENT_EOF) return 0; fatent_init(&fatent); ret = fat_ent_read(inode, &fatent, dclus); if (ret == FAT_ENT_EOF) { fatent_brelse(&fatent); return 0; } else if (ret == FAT_ENT_FREE) { fat_fs_panic(sb, "%s: invalid cluster chain (i_pos %lld)", __FUNCTION__, MSDOS_I(inode)->i_pos); ret = -EIO; } else if (ret > 0) { err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait); if (err) ret = err; } fatent_brelse(&fatent); if (ret < 0) return ret; free_start = ret; } inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9); /* Freeing the remained cluster chain */ return fat_free_clusters(inode, free_start); }
static int fat_ioctl_get_volume_id(struct inode *inode, u32 __user *user_attr) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); return put_user(sbi->vol_id, user_attr); }
int fat_generic_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); u32 __user *user_attr = (u32 __user *)arg; switch (cmd) { case FAT_IOCTL_GET_ATTRIBUTES: { u32 attr; if (inode->i_ino == MSDOS_ROOT_INO) attr = ATTR_DIR; else attr = fat_attr(inode); return put_user(attr, user_attr); } case FAT_IOCTL_SET_ATTRIBUTES: { u32 attr, oldattr; int err, is_dir = S_ISDIR(inode->i_mode); struct iattr ia; err = get_user(attr, user_attr); if (err) return err; mutex_lock(&inode->i_mutex); if (IS_RDONLY(inode)) { err = -EROFS; goto up; } /* * ATTR_VOLUME and ATTR_DIR cannot be changed; this also * prevents the user from turning us into a VFAT * longname entry. Also, we obviously can't set * any of the NTFS attributes in the high 24 bits. */ attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); /* Merge in ATTR_VOLUME and ATTR_DIR */ attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | (is_dir ? ATTR_DIR : 0); oldattr = fat_attr(inode); /* Equivalent to a chmod() */ ia.ia_valid = ATTR_MODE | ATTR_CTIME; if (is_dir) { ia.ia_mode = MSDOS_MKMODE(attr, S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR; } else { ia.ia_mode = MSDOS_MKMODE(attr, (S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)) & ~sbi->options.fs_fmask) | S_IFREG; } /* The root directory has no attributes */ if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { err = -EINVAL; goto up; } if (sbi->options.sys_immutable) { if ((attr | oldattr) & ATTR_SYS) { if (!capable(CAP_LINUX_IMMUTABLE)) { err = -EPERM; goto up; } } } /* This MUST be done before doing anything irreversible... */ err = notify_change(filp->f_path.dentry, &ia); if (err) goto up; if (sbi->options.sys_immutable) { if (attr & ATTR_SYS) inode->i_flags |= S_IMMUTABLE; else inode->i_flags &= S_IMMUTABLE; } MSDOS_I(inode)->i_attrs = attr & ATTR_UNUSED; mark_inode_dirty(inode); up: mutex_unlock(&inode->i_mutex); return err; } default: return -ENOTTY; /* Inappropriate ioctl for device */ } }
int fat_is_uptodate(struct super_block *sb, struct buffer_head *bh) { return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh); }
void fat_mark_buffer_dirty ( struct super_block *sb, struct buffer_head *bh) { MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh); }
/***** Make a directory */ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode) { struct super_block *sb = dir->i_sb; struct buffer_head *bh; struct msdos_dir_entry *de; struct inode *inode; int res,is_hid; unsigned char msdos_name[MSDOS_NAME]; loff_t i_pos; lock_kernel(); res = msdos_format_name(dentry->d_name.name,dentry->d_name.len, msdos_name, &MSDOS_SB(sb)->options); if (res < 0) { unlock_kernel(); return res; } is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); /* foo vs .foo situation */ if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) goto out_exist; res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid); if (res) goto out_unlock; inode = fat_build_inode(dir->i_sb, de, i_pos, &res); if (!inode) { brelse(bh); goto out_unlock; } res = 0; dir->i_nlink++; inode->i_nlink = 2; /* no need to mark them dirty */ res = fat_new_dir(inode, dir, 0); if (res) goto mkdir_error; brelse(bh); d_instantiate(dentry, inode); res = 0; out_unlock: unlock_kernel(); return res; mkdir_error: inode->i_nlink = 0; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_nlink--; mark_inode_dirty(inode); mark_inode_dirty(dir); de->name[0] = DELETED_FLAG; mark_buffer_dirty(bh); brelse(bh); fat_detach(inode); iput(inode); goto out_unlock; out_exist: brelse(bh); res = -EINVAL; goto out_unlock; }
static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr) { struct inode *inode = file_inode(file); struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); int is_dir = S_ISDIR(inode->i_mode); u32 attr, oldattr; struct iattr ia; int err; err = get_user(attr, user_attr); if (err) goto out; err = mnt_want_write_file(file); if (err) goto out; inode_lock(inode); /* * ATTR_VOLUME and ATTR_DIR cannot be changed; this also * prevents the user from turning us into a VFAT * longname entry. Also, we obviously can't set * any of the NTFS attributes in the high 24 bits. */ attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); /* Merge in ATTR_VOLUME and ATTR_DIR */ attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | (is_dir ? ATTR_DIR : 0); oldattr = fat_make_attrs(inode); /* Equivalent to a chmod() */ ia.ia_valid = ATTR_MODE | ATTR_CTIME; ia.ia_ctime = current_time(inode); if (is_dir) ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); else { ia.ia_mode = fat_make_mode(sbi, attr, S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); } /* The root directory has no attributes */ if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { err = -EINVAL; goto out_unlock_inode; } if (sbi->options.sys_immutable && ((attr | oldattr) & ATTR_SYS) && !capable(CAP_LINUX_IMMUTABLE)) { err = -EPERM; goto out_unlock_inode; } /* * The security check is questionable... We single * out the RO attribute for checking by the security * module, just because it maps to a file mode. */ err = security_inode_setattr(file->f_path.dentry, &ia); if (err) goto out_unlock_inode; /* This MUST be done before doing anything irreversible... */ err = fat_setattr(file->f_path.dentry, &ia); if (err) goto out_unlock_inode; fsnotify_change(file->f_path.dentry, ia.ia_valid); if (sbi->options.sys_immutable) { if (attr & ATTR_SYS) inode->i_flags |= S_IMMUTABLE; else inode->i_flags &= ~S_IMMUTABLE; } fat_save_attrs(inode, attr); mark_inode_dirty(inode); out_unlock_inode: inode_unlock(inode); mnt_drop_write_file(file); out: return err; }
/***** Make a directory */ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode) { struct super_block *sb = dir->i_sb; struct buffer_head *bh; struct msdos_dir_entry *de; struct inode *inode; int res,is_hid; char msdos_name[MSDOS_NAME]; loff_t ino; res = msdos_format_name(dentry->d_name.name,dentry->d_name.len, msdos_name, &MSDOS_SB(sb)->options); if (res < 0) return res; is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); /* foo vs .foo situation */ if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0) goto out_exist; res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 1, is_hid); if (res) goto out_unlock; inode = fat_build_inode(dir->i_sb, de, ino, &res); if (!inode) { fat_brelse(sb, bh); goto out_unlock; } res = 0; dir->i_nlink++; inode->i_nlink = 2; /* no need to mark them dirty */ res = fat_new_dir(inode, dir, 0); if (res) goto mkdir_error; fat_brelse(sb, bh); d_instantiate(dentry, inode); res = 0; out_unlock: return res; mkdir_error: printk(KERN_WARNING "msdos_mkdir: error=%d, attempting cleanup\n", res); inode->i_nlink = 0; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_nlink--; mark_inode_dirty(inode); mark_inode_dirty(dir); de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, bh); fat_brelse(sb, bh); fat_detach(inode); iput(inode); goto out_unlock; out_exist: fat_brelse(sb, bh); res = -EINVAL; goto out_unlock; }
unsigned long fat_find_free_clusters(struct super_block *sb, unsigned long clusterSum, int *contiguous) { struct msdos_sb_info *sbi = MSDOS_SB(sb); struct fatent_operations *ops = sbi->fatent_ops; struct fat_entry fatent; unsigned long reada_blocks, reada_mask, cur_block; int err = 0, free; unsigned long clusters = 0; unsigned long start = 0; *contiguous = 0; lock_fat2(sbi); if (sbi->free_clusters != -1 && sbi->free_clus_valid && sbi->free_clusters < clusterSum) { printk(KERN_INFO "fat_find_free_clusters failed, free_clusters:%d, free_clus_valid:%d\n", sbi->free_clusters, sbi->free_clus_valid); start = 0; goto out2; } reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits; reada_mask = reada_blocks - 1; cur_block = 0; free = 0; fatent_init(&fatent); fatent_set_entry(&fatent, FAT_START_ENT); while (fatent.entry < sbi->max_cluster) { /* readahead of fat blocks */ /*if ((cur_block & reada_mask) == 0) { unsigned long rest = sbi->fat_length - cur_block; fat_ent_reada2(sb, &fatent, min(reada_blocks, rest)); } cur_block++;*/ fatent_set_entry(&fatent, fatent.entry); err = fat_ent_read_block2(sb, &fatent); if (err) { printk(KERN_INFO "fat_find_first_free_clusters fat_ent_read_block2 failed\n"); start = 0; goto out1; } do { if (ops->ent_get(&fatent) == FAT_ENT_FREE) { free++; if (start == 0) { start = fatent.entry; } clusters++; if (clusters >= clusterSum) { //printk(KERN_INFO "fat_find_free_clusters start = %ld\n", start); start--; if (start < FAT_START_ENT) { start = sbi->max_cluster - 1; } sbi->prev_free = start; sb->s_dirt = 1; *contiguous = 1; goto out1; } } else { start = 0; clusters = 0; } if (fatent.entry >= sbi->max_cluster) { start = 0; break; } } while (fat_ent_next2(sbi, &fatent)); } out1: //sbi->free_clusters = free; //sbi->free_clus_valid = 1; //sb->s_dirt = 1; fatent_brelse(&fatent); out2: unlock_fat2(sbi); return start; }
static void setup(struct super_block *sb) { MSDOS_SB(sb)->dir_ops = &vxext_dir_inode_operations; sb->s_d_op = &vxext_dentry_operations; sb->s_flags |= MS_NOATIME; }
struct buffer_head *fat_getblk(struct super_block *sb, int block) { return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block); }