📄 dir.c
字号:
goto RecEnd; if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME)) goto RecEnd; if (de->attr != ATTR_EXT && IS_FREE(de->name)) goto RecEnd; } else { if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) goto RecEnd; } if (isvfat && de->attr == ATTR_EXT) { struct msdos_dir_slot *ds; unsigned char id; unsigned char slot; unsigned char slots; unsigned char sum; unsigned char alias_checksum; if (!unicode) { unicode = (wchar_t *) __get_free_page(GFP_KERNEL); if (!unicode) { filp->f_pos = cpos; fat_brelse(sb, bh); return -ENOMEM; } }ParseLong: slots = 0; ds = (struct msdos_dir_slot *) de; id = ds->id; if (!(id & 0x40)) goto RecEnd; slots = id & ~0x40; if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */ goto RecEnd; long_slots = slots; alias_checksum = ds->alias_checksum; slot = slots; while (1) { int offset; slot--; offset = slot * 13; fat16_towchar(unicode + offset, ds->name0_4, 5); fat16_towchar(unicode + offset + 5, ds->name5_10, 6); fat16_towchar(unicode + offset + 11, ds->name11_12, 2); if (ds->id & 0x40) { unicode[offset + 13] = 0; } if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1) goto EODir; if (slot == 0) break; ds = (struct msdos_dir_slot *) de; if (ds->attr != ATTR_EXT) goto RecEnd; /* XXX */ if ((ds->id & ~0x40) != slot) goto ParseLong; if (ds->alias_checksum != alias_checksum) goto ParseLong; } if (de->name[0] == (__s8) DELETED_FLAG) goto RecEnd; if (de->attr == ATTR_EXT) goto ParseLong; if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME)) goto RecEnd; for (sum = 0, i = 0; i < 11; i++) sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i]; if (sum != alias_checksum) long_slots = 0; } if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) { *ptname++ = '.'; dotoffset = 1; } for (i = 0; i < 8; i++) { /* see namei.c, msdos_format_name */ if (de->name[i] == 0x05) work[i] = 0xE5; else work[i] = de->name[i]; } for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) { if (!(c = work[i])) break; chl = fat_shortname2uni(nls_disk, &work[i], 8 - i, &bufuname[j++], opt_shortname, de->lcase & CASE_LOWER_BASE); if (chl <= 1) { ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c; if (c != ' ') { last = i; last_u = j; } } else { last_u = j; for (chi = 0; chi < chl && i < 8; chi++) { ptname[i] = work[i]; i++; last = i; } } } i = last; j = last_u; fat_short2uni(nls_disk, ".", 1, &bufuname[j++]); ptname[i++] = '.'; for (i2 = 0; i2 < 3;) { if (!(c = de->ext[i2])) break; chl = fat_shortname2uni(nls_disk, &de->ext[i2], 3 - i2, &bufuname[j++], opt_shortname, de->lcase & CASE_LOWER_EXT); if (chl <= 1) { i2++; ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c; if (c != ' ') { last = i; last_u = j; } } else { last_u = j; for (chi = 0; chi < chl && i2 < 3; chi++) { ptname[i++] = de->ext[i2++]; last = i; } } } if (!last) goto RecEnd; i = last + dotoffset; j = last_u; lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry); if (!memcmp(de->name,MSDOS_DOT,11)) inum = inode->i_ino; else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {/* inum = fat_parent_ino(inode,0); */ inum = filp->f_dentry->d_parent->d_inode->i_ino; } else { struct inode *tmp = fat_iget(sb, ino); if (tmp) { inum = tmp->i_ino; iput(tmp); } else inum = iunique(sb, MSDOS_ROOT_INO); } if (isvfat) { bufuname[j] = 0x0000; i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io); } if (!long_slots||shortnames) { if (both) bufname[i] = '\0'; if (filldir(dirent, bufname, i, *furrfu, inum, (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0) goto FillFailed; } else { char longname[275]; int long_len = utf8 ? utf8_wcstombs(longname, unicode, sizeof(longname)) : uni16_to_x8(longname, unicode, uni_xlate, nls_io); if (both) { memcpy(&longname[long_len+1], bufname, i); long_len += i; } if (filldir(dirent, longname, long_len, *furrfu, inum, (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0) goto FillFailed; }RecEnd: furrfu = &lpos; filp->f_pos = cpos; goto GetNew;EODir: filp->f_pos = cpos;FillFailed: if (bh) fat_brelse(sb, bh); if (unicode) { free_page((unsigned long) unicode); } return 0;}int fat_readdir(struct file *filp, void *dirent, filldir_t filldir){ struct inode *inode = filp->f_dentry->d_inode; return fat_readdirx(inode, filp, dirent, filldir, 0, 0);}static int vfat_ioctl_fill( void * buf, const char * name, int name_len, loff_t offset, ino_t ino, unsigned int d_type){ struct dirent *d1 = (struct dirent *)buf; struct dirent *d2 = d1 + 1; int len, slen; int dotdir; get_user(len, &d1->d_reclen); if (len != 0) { return -1; } if ((name_len == 1 && name[0] == '.') || (name_len == 2 && name[0] == '.' && name[1] == '.')) { dotdir = 1; len = name_len; } else { dotdir = 0; len = strlen(name); } if (len != name_len) { copy_to_user(d2->d_name, name, len); put_user(0, d2->d_name + len); put_user(len, &d2->d_reclen); put_user(ino, &d2->d_ino); put_user(offset, &d2->d_off); slen = name_len - len; copy_to_user(d1->d_name, name+len+1, slen); put_user(0, d1->d_name+slen); put_user(slen, &d1->d_reclen); } else { put_user(0, d2->d_name); put_user(0, &d2->d_reclen); copy_to_user(d1->d_name, name, len); put_user(0, d1->d_name+len); put_user(len, &d1->d_reclen); } PRINTK(("FAT d1=%p d2=%p len=%d, name_len=%d\n", d1, d2, len, name_len)); return 0;}int fat_dir_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg){ int err; /* * We want to provide an interface for Samba to be able * to get the short filename for a given long filename. * Samba should use this ioctl instead of readdir() to * get the information it needs. */ switch (cmd) { case VFAT_IOCTL_READDIR_BOTH: { struct dirent *d1 = (struct dirent *)arg; err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2])); if (err) return err; put_user(0, &d1->d_reclen); return fat_readdirx(inode,filp,(void *)arg, vfat_ioctl_fill, 0, 1); } case VFAT_IOCTL_READDIR_SHORT: { struct dirent *d1 = (struct dirent *)arg; put_user(0, &d1->d_reclen); err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2])); if (err) return err; return fat_readdirx(inode,filp,(void *)arg, vfat_ioctl_fill, 1, 1); } default: /* forward ioctl to CVF extension */ if (MSDOS_SB(inode->i_sb)->cvf_format && MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl) return MSDOS_SB(inode->i_sb)->cvf_format ->cvf_dir_ioctl(inode,filp,cmd,arg); return -EINVAL; } return 0;}/***** See if directory is empty */int fat_dir_empty(struct inode *dir){ loff_t pos; struct buffer_head *bh; struct msdos_dir_entry *de; int ino,result = 0; pos = 0; bh = NULL; while (fat_get_entry(dir,&pos,&bh,&de,&ino) > -1) { /* Ignore vfat longname entries */ if (de->attr == ATTR_EXT) continue; if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT , MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) { result = -ENOTEMPTY; break; } } if (bh) fat_brelse(dir->i_sb, bh); return result;}/* This assumes that size of cluster is above the 32*slots */int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh, struct msdos_dir_entry **de, int *ino){ struct super_block *sb = dir->i_sb; loff_t offset, curr; int row; struct buffer_head *new_bh; offset = curr = 0; *bh = NULL; row = 0; while (fat_get_entry(dir,&curr,bh,de,ino) > -1) { if (IS_FREE((*de)->name)) { if (++row == slots) return offset; } else { row = 0; offset = curr; } } if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32)) return -ENOSPC; new_bh = fat_extend_dir(dir); if (!new_bh) return -ENOSPC; fat_brelse(sb, new_bh); do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots); return offset;}int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat){ struct super_block *sb = dir->i_sb; struct buffer_head *bh; struct msdos_dir_entry *de; __u16 date, time; if ((bh = fat_extend_dir(dir)) == NULL) return -ENOSPC; /* zeroed out, so... */ fat_date_unix2dos(dir->i_mtime,&time,&date); de = (struct msdos_dir_entry*)&bh->b_data[0]; memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME); memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME); de[0].attr = de[1].attr = ATTR_DIR; de[0].time = de[1].time = CT_LE_W(time); de[0].date = de[1].date = CT_LE_W(date); if (is_vfat) { /* extra timestamps */ de[0].ctime = de[1].ctime = CT_LE_W(time); de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = CT_LE_W(date); } de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart); de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16); de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart); de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16); fat_mark_buffer_dirty(sb, bh); fat_brelse(sb, bh); dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); return 0;}/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 8 * c-brace-imaginary-offset: 0 * c-brace-offset: -8 * c-argdecl-indent: 8 * c-label-offset: -8 * c-continued-statement-offset: 8 * c-continued-brace-offset: 0 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -