static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir) { struct inode *dir = filp->f_dentry->d_inode; struct RDIR_FILLDIR bufk; bufk.filldir = filldir; bufk.dirbuf = dirbuf; bufk.real_root = pseudo_root && (dir == saved_root->d_inode); return fat_readdir (filp, &bufk, rdir_filldir); }
static int UMSDOS_rreaddir ( struct inode *dir, struct file *filp, void *dirbuf, filldir_t filldir) { struct RDIR_FILLDIR bufk; bufk.filldir = filldir; bufk.dirbuf = dirbuf; bufk.real_root = pseudo_root != NULL && dir == dir->i_sb->s_mounted && dir == pseudo_root->i_sb->s_mounted; return fat_readdir(dir,filp,&bufk,rdir_filldir); }
void print_tree(struct fat_vol_handle *vol, struct fat_file_handle *dir, int nest) { struct fat_file_handle subdir; struct dirent ent; while(!fat_readdir(dir, &ent)) { if((strcmp(ent.d_name, ".") == 0) || (strcmp(ent.d_name, "..") == 0)) continue; for(int i = 0; i < nest; i++) printf("\t"); printf("%s\n", ent.d_name); if(ent.fat_attr == FAT_ATTR_DIRECTORY) { fat_chdir(vol, ent.d_name); assert(fat_open(vol, ".", 0, &subdir) == 0); print_tree(vol, &subdir, nest + 1); fat_chdir(vol, ".."); } } }
int music_add_dir(const char *spath, const char *lpath) { p_fat_info info; dword i, count; if (spath == NULL || lpath == NULL) return -EINVAL; count = fat_readdir(lpath, (char *) spath, &info); if (count == INVALID) return -EBADF; for (i = 0; i < count; i++) { char sfn[PATH_MAX]; char lfn[PATH_MAX]; if ((info[i].attr & FAT_FILEATTR_DIRECTORY) > 0) { char lpath2[PATH_MAX], spath2[PATH_MAX]; if (info[i].filename[0] == '.') continue; SPRINTF_S(lpath2, "%s%s/", lpath, info[i].longname); SPRINTF_S(spath2, "%s%s/", spath, info[i].filename); music_add_dir(spath2, lpath2); continue; } if (fs_is_music(info[i].filename, info[i].longname) == false) continue; SPRINTF_S(sfn, "%s%s", spath, info[i].filename); SPRINTF_S(lfn, "%s%s", lpath, info[i].longname); music_add(sfn, lfn); } free((void *) info); return 0; }
void print_tree(struct fat_vol_handle *vol, struct fat_file_handle *dir, const char *path) { struct dirent ent; char tmppath[1024]; struct fat_file_handle subdir; while(!fat_readdir(dir, &ent)) { if((strcmp(ent.d_name, ".") == 0) || (strcmp(ent.d_name, "..") == 0)) continue; sprintf(tmppath, "%s/%s", path, ent.d_name); puts(tmppath); if(ent.fat_attr == FAT_ATTR_DIRECTORY) { fat_chdir(vol, ent.d_name); assert(fat_open(vol, ".", 0, &subdir) == 0); print_tree(vol, &subdir, tmppath); fat_chdir(vol, ".."); } } }
int upload_file(char *name,char *dest_name) { struct dirent de; int retVal=0; do { struct stat st; if (stat(name,&st)) { fprintf(stderr,"ERROR: Could not stat file '%s'\n",name); perror("stat() failed"); } printf("File '%s' is %ld bytes long.\n",name,(long)st.st_size); if (!file_system_found) open_file_system(); if (!file_system_found) { fprintf(stderr,"ERROR: Could not open file system.\n"); retVal=-1; break; } if (fat_opendir("/")) { retVal=-1; break; } printf("Opened directory, dir_sector=%d (absolute sector = %d)\n",dir_sector,partition_start+dir_sector); while(!fat_readdir(&de)) { if (de.d_name[0]) printf("%13s %d\n",de.d_name,(int)de.d_off); // else dump_bytes(0,"empty dirent",&dir_sector_buffer[dir_sector_offset],32); if (!strcasecmp(de.d_name,dest_name)) { // Found file, so will replace it printf("%s already exists on the file system, beginning at cluster %d\n",name,(int)de.d_ino); break; } } if (dir_sector==-1) { // File does not (yet) exist, get ready to create it printf("%s does not yet exist on the file system -- searching for empty directory slot to create it in.\n",name); if (fat_opendir("/")) { retVal=-1; break; } struct dirent de; while(!fat_readdir(&de)) { if (!de.d_name[0]) { printf("Found empty slot at dir_sector=%d, dir_sector_offset=%d\n", dir_sector,dir_sector_offset); // Create directory entry, and write sector back to SD card unsigned char dir[32]; bzero(dir,32); // Write name for(int i=0;i<11;i++) dir[i]=0x20; for(int i=0;i<8;i++) if (dest_name[i]=='.') { // Write out extension for(int j=0;j<3;j++) if (dest_name[i+1+j]) dir[8+j]=dest_name[i+1+j]; break; } else if (!dest_name[i]) break; else dir[i]=dest_name[i]; // Set file attributes (only archive bit) dir[0xb]=0x20; // Store create time and date time_t t=time(0); struct tm *tm=localtime(&t); dir[0xe]=(tm->tm_sec>>1)&0x1F; // 2 second resolution dir[0xe]|=(tm->tm_min&0x7)<<5; dir[0xf]=(tm->tm_min&0x3)>>3; dir[0xf]|=(tm->tm_hour)<<2; dir[0x10]=tm->tm_mday&0x1f; dir[0x10]|=((tm->tm_mon+1)&0x7)<<5; dir[0x11]=((tm->tm_mon+1)&0x1)>>3; dir[0x11]|=(tm->tm_year-80)<<1; dump_bytes(0,"New directory entry",dir,32); // (Cluster and size we set after writing to the file) // Copy back into directory sector, and write it bcopy(dir,&dir_sector_buffer[dir_sector_offset],32); if (write_sector(partition_start+dir_sector,dir_sector_buffer)) { printf("Failed to write updated directory sector.\n"); retVal=-1; break; } break; } } }
/* #Specification: ioctl / prototypes * The official prototype for the umsdos ioctl on directory * is: * * int ioctl ( * int fd, // File handle of the directory * int cmd, // command * struct umsdos_ioctl *data) * * The struct and the commands are defined in linux/umsdos_fs.h. * * umsdos_progs/umsdosio.c provide an interface in C++ to all * these ioctl. umsdos_progs/udosctl is a small utility showing * all this. * * These ioctl generally allow one to work on the EMD or the * DOS directory independently. These are essential to implement * the synchronise. */ int UMSDOS_ioctl_dir(struct inode *dir, struct file *filp, unsigned int cmd, unsigned long data_ptr) { struct dentry *dentry = filp->f_dentry; struct umsdos_ioctl *idata = (struct umsdos_ioctl *) data_ptr; int ret; struct file new_filp; struct umsdos_ioctl data; Printk(("UMSDOS_ioctl_dir: %s/%s, cmd=%d, data=%08lx\n", dentry->d_parent->d_name.name, dentry->d_name.name, cmd, data_ptr)); /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */ if (cmd != UMSDOS_GETVERSION && cmd != UMSDOS_READDIR_DOS && cmd != UMSDOS_READDIR_EMD && cmd != UMSDOS_INIT_EMD && cmd != UMSDOS_CREAT_EMD && cmd != UMSDOS_RENAME_DOS && cmd != UMSDOS_UNLINK_EMD && cmd != UMSDOS_UNLINK_DOS && cmd != UMSDOS_RMDIR_DOS && cmd != UMSDOS_STAT_DOS && cmd != UMSDOS_DOS_SETUP) return fat_dir_ioctl (dir, filp, cmd, data_ptr); /* #Specification: ioctl / acces * Only root (effective id) is allowed to do IOCTL on directory * in UMSDOS. EPERM is returned for other user. */ /* * Well, not all cases require write access, but it simplifies * the code, and let's face it, there is only one client (umssync) * for all this. */ ret = verify_area (VERIFY_WRITE, (void *) data_ptr, sizeof (struct umsdos_ioctl)); if (ret < 0) goto out; ret = -EPERM; if (current->euid != 0 && cmd != UMSDOS_GETVERSION) goto out; ret = -EINVAL; if (cmd == UMSDOS_GETVERSION) { /* #Specification: ioctl / UMSDOS_GETVERSION * The field version and release of the structure * umsdos_ioctl are filled with the version and release * number of the fs code in the kernel. This will allow * some form of checking. Users won't be able to run * incompatible utility such as the synchroniser (umssync). * umsdos_progs/umsdosio.c enforce this checking. * * Return always 0. */ put_user (UMSDOS_VERSION, &idata->version); put_user (UMSDOS_RELEASE, &idata->release); ret = 0; goto out; } if (cmd == UMSDOS_READDIR_DOS) { /* #Specification: ioctl / UMSDOS_READDIR_DOS * One entry is read from the DOS directory at the current * file position. The entry is put as is in the dos_dirent * field of struct umsdos_ioctl. * * Return > 0 if success. */ struct UMSDOS_DIR_ONCE bufk; bufk.count = 0; bufk.ent = &idata->dos_dirent; fat_readdir (filp, &bufk, umsdos_ioctl_fill); ret = bufk.count == 1 ? 1 : 0; goto out; } if (cmd == UMSDOS_READDIR_EMD) { /* #Specification: ioctl / UMSDOS_READDIR_EMD * One entry is read from the EMD at the current * file position. The entry is put as is in the umsdos_dirent * field of struct umsdos_ioctl. The corresponding mangled * DOS entry name is put in the dos_dirent field. * * All entries are read including hidden links. Blank * entries are skipped. * * Return > 0 if success. */ struct dentry *demd; /* The absence of the EMD is simply seen as an EOF */ demd = umsdos_get_emd_dentry(dentry); ret = PTR_ERR(demd); if (IS_ERR(demd)) goto out; ret = 0; if (!demd->d_inode) goto read_dput; fill_new_filp(&new_filp, demd); new_filp.f_pos = filp->f_pos; while (new_filp.f_pos < demd->d_inode->i_size) { off_t f_pos = new_filp.f_pos; struct umsdos_dirent entry; struct umsdos_info info; ret = umsdos_emd_dir_readentry (&new_filp, &entry); if (ret) break; if (entry.name_len <= 0) continue; umsdos_parse (entry.name, entry.name_len, &info); info.f_pos = f_pos; umsdos_manglename (&info); ret = -EFAULT; if (copy_to_user (&idata->umsdos_dirent, &entry, sizeof (entry))) break; if (copy_to_user (&idata->dos_dirent.d_name, info.fake.fname, info.fake.len + 1)) break; ret = entry.name_len; break; } /* update the original f_pos */ filp->f_pos = new_filp.f_pos; read_dput: d_drop(demd); dput(demd); goto out; } if (cmd == UMSDOS_INIT_EMD) { /* #Specification: ioctl / UMSDOS_INIT_EMD * The UMSDOS_INIT_EMD command makes sure the EMD * exists for a directory. If it does not, it is * created. Also, it makes sure the directory function * table (struct inode_operations) is set to the UMSDOS * semantic. This mean that umssync may be applied to * an "opened" msdos directory, and it will change behavior * on the fly. * * Return 0 if success. */ extern struct inode_operations umsdos_rdir_inode_operations; ret = umsdos_make_emd(dentry); Printk(("UMSDOS_ioctl_dir: INIT_EMD %s/%s, ret=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, ret)); dir->i_op = (ret == 0) ? &umsdos_dir_inode_operations : &umsdos_rdir_inode_operations; goto out; } ret = -EFAULT; if (copy_from_user (&data, idata, sizeof (data))) goto out; if (cmd == UMSDOS_CREAT_EMD) { /* #Specification: ioctl / UMSDOS_CREAT_EMD * The umsdos_dirent field of the struct umsdos_ioctl is used * as is to create a new entry in the EMD of the directory. * The DOS directory is not modified. * No validation is done (yet). * * Return 0 if success. */ struct umsdos_info info; /* This makes sure info.entry and info in general * is correctly initialised */ memcpy (&info.entry, &data.umsdos_dirent, sizeof (data.umsdos_dirent)); umsdos_parse (data.umsdos_dirent.name ,data.umsdos_dirent.name_len, &info); ret = umsdos_newentry (dentry, &info); goto out; } else if (cmd == UMSDOS_RENAME_DOS) { struct dentry *old_dentry, *new_dentry; /* FIXME */ /* #Specification: ioctl / UMSDOS_RENAME_DOS * A file or directory is renamed in a DOS directory * (not moved across directory). The source name * is in the dos_dirent.name field and the destination * is in umsdos_dirent.name field. * * This ioctl allows umssync to rename a mangled file * name before syncing it back in the EMD. */ old_dentry = umsdos_lookup_dentry (dentry, data.dos_dirent.d_name, data.dos_dirent.d_reclen ,1); ret = PTR_ERR(old_dentry); if (IS_ERR(old_dentry)) goto out; new_dentry = umsdos_lookup_dentry (dentry, data.umsdos_dirent.name, data.umsdos_dirent.name_len, 1); ret = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { printk("umsdos_ioctl: renaming %s/%s to %s/%s\n", old_dentry->d_parent->d_name.name, old_dentry->d_name.name, new_dentry->d_parent->d_name.name, new_dentry->d_name.name); ret = msdos_rename (dir, old_dentry, dir, new_dentry); dput(new_dentry); } dput(old_dentry); goto out; } else if (cmd == UMSDOS_UNLINK_EMD) { /* #Specification: ioctl / UMSDOS_UNLINK_EMD * The umsdos_dirent field of the struct umsdos_ioctl is used * as is to remove an entry from the EMD of the directory. * No validation is done (yet). The mode field is used * to validate S_ISDIR or S_ISREG. * * Return 0 if success. */ struct umsdos_info info; /* This makes sure info.entry and info in general * is correctly initialised */ memcpy (&info.entry, &data.umsdos_dirent, sizeof (data.umsdos_dirent)); umsdos_parse (data.umsdos_dirent.name, data.umsdos_dirent.name_len, &info); ret = umsdos_delentry (dentry, &info, S_ISDIR (data.umsdos_dirent.mode)); if (ret) { printk(KERN_WARNING "umsdos_ioctl: delentry %s/%s failed, ret=%d\n", dentry->d_name.name, info.entry.name, ret); } goto out; } else if (cmd == UMSDOS_UNLINK_DOS) { struct dentry *temp; /* #Specification: ioctl / UMSDOS_UNLINK_DOS * The dos_dirent field of the struct umsdos_ioctl is used to * execute a msdos_unlink operation. The d_name and d_reclen * fields are used. * * Return 0 if success. */ temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name, data.dos_dirent.d_reclen, 1); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out; ret = -ENOENT; if (temp->d_inode) { ret = -EISDIR; if (!S_ISDIR(temp->d_inode->i_mode)) ret = msdos_unlink (dir, temp); } dput (temp); goto out; } else if (cmd == UMSDOS_RMDIR_DOS) { struct dentry *temp; /* #Specification: ioctl / UMSDOS_RMDIR_DOS * The dos_dirent field of the struct umsdos_ioctl is used to * execute a msdos_rmdir operation. The d_name and d_reclen * fields are used. * * Return 0 if success. */ temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name, data.dos_dirent.d_reclen, 1); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out; ret = -ENOENT; if (temp->d_inode) { ret = -ENOTDIR; if (S_ISDIR(temp->d_inode->i_mode)) ret = msdos_rmdir (dir, temp); } dput (temp); goto out; } else if (cmd == UMSDOS_STAT_DOS) { /* #Specification: ioctl / UMSDOS_STAT_DOS * The dos_dirent field of the struct umsdos_ioctl is * used to execute a stat operation in the DOS directory. * The d_name and d_reclen fields are used. * * The following field of umsdos_ioctl.stat are filled. * * st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime, * Return 0 if success. */ struct dentry *dret; struct inode *inode; dret = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name, data.dos_dirent.d_reclen, 1); ret = PTR_ERR(dret); if (IS_ERR(dret)) goto out; ret = -ENOENT; inode = dret->d_inode; if (inode) { data.stat.st_ino = inode->i_ino; data.stat.st_mode = inode->i_mode; data.stat.st_size = inode->i_size; data.stat.st_atime = inode->i_atime; data.stat.st_ctime = inode->i_ctime; data.stat.st_mtime = inode->i_mtime; ret = -EFAULT; if (!copy_to_user (&idata->stat, &data.stat, sizeof (data.stat))) ret = 0; } dput(dret); goto out; } else if (cmd == UMSDOS_DOS_SETUP) { /* #Specification: ioctl / UMSDOS_DOS_SETUP * The UMSDOS_DOS_SETUP ioctl allow changing the * default permission of the MS-DOS filesystem driver * on the fly. The MS-DOS driver applies global permissions * to every file and directory. Normally these permissions * are controlled by a mount option. This is not * available for root partition, so a special utility * (umssetup) is provided to do this, normally in * /etc/rc.local. * * Be aware that this applies ONLY to MS-DOS directories * (those without EMD --linux-.---). Umsdos directory * have independent (standard) permission for each * and every file. * * The field umsdos_dirent provide the information needed. * umsdos_dirent.uid and gid sets the owner and group. * umsdos_dirent.mode set the permissions flags. */ dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid; dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid; dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode; ret = 0; } out: Printk (("ioctl %d, returning %d\n", cmd, ret)); return ret; }
int fat_request(DWORD Function, void *Params) { int Res; switch (Function) { case FD32_READ: { fd32_read_t *X = (fd32_read_t *) Params; tFile *F; if (X->Size < sizeof(fd32_read_t)) return EINVAL; F = (tFile *) X->DeviceId; if (F->FilSig != FAT_FILSIG) return EBADF; #ifdef FATREMOVABLE if ((Res = fat_mediachange(F->V)) < 0) return Res; #endif return fat_read(F, X->Buffer, X->BufferBytes); } case FD32_WRITE: { #ifdef FATWRITE fd32_write_t *X = (fd32_write_t *) Params; tFile *F; if (X->Size < sizeof(fd32_write_t)) return EINVAL; F = (tFile *) X->DeviceId; if (F->FilSig != FAT_FILSIG) return EBADF; #ifdef FATREMOVABLE if ((Res = fat_mediachange(F->V)) < 0) return Res; #endif return fat_write(F, X->Buffer, X->BufferBytes); #else return EROFS; #endif } case FD32_LSEEK: { fd32_lseek_t *X = (fd32_lseek_t *) Params; if (X->Size < sizeof(fd32_lseek_t)) return EINVAL; if (((tFile *) X->DeviceId)->FilSig != FAT_FILSIG) return EBADF; return fat_lseek((tFile *) X->DeviceId, &X->Offset, X->Origin); } case FD32_OPENFILE: { fd32_openfile_t *X = (fd32_openfile_t *) Params; tVolume *V; if (X->Size < sizeof(fd32_openfile_t)) return EINVAL; V = (tVolume *) X->DeviceId; if (V->VolSig != FAT_VOLSIG) return ENODEV; #ifdef FATREMOVABLE if ((Res = fat_mediachange(V)) < 0) return Res; #endif return fat_open(V, X->FileName, X->Mode, X->Attr, X->AliasHint, (tFile **) &X->FileId); } case FD32_CLOSE: { fd32_close_t *X = (fd32_close_t *) Params; tFile *F; if (X->Size < sizeof(fd32_close_t)) return EINVAL; F = (tFile *) X->DeviceId; if (F->FilSig != FAT_FILSIG) return EBADF; #ifdef FATREMOVABLE if ((Res = fat_mediachange(F->V)) < 0) return Res; #endif return fat_close(F); } case FD32_READDIR: { fd32_readdir_t *X = (fd32_readdir_t *) Params; tFile *F; if (X->Size < sizeof(fd32_readdir_t)) return EINVAL; F = (tFile *) X->DirId; if (F->FilSig != FAT_FILSIG) return EBADF; #ifdef FATREMOVABLE if ((Res = fat_mediachange(F->V)) < 0) return Res; #endif return fat_readdir(F, (fd32_fs_lfnfind_t *) X->Entry); } case FD32_FFLUSH: { #ifdef FATWRITE fd32_fflush_t *X = (fd32_fflush_t *) Params; tFile *F; if (X->Size < sizeof(fd32_fflush_t)) return EINVAL; F = (tFile *) X->DeviceId; if (F->FilSig != FAT_FILSIG) return EBADF; #ifdef FATREMOVABLE if ((Res = fat_mediachange(F->V)) < 0) return Res; #endif return fat_fflush(F); #else return EROFS; #endif } case FD32_OPEN: { fd32_open_t *X = (fd32_open_t *) Params; if (X->Size < sizeof(fd32_open_t)) return EINVAL; if (((tFile *) X->DeviceId)->FilSig != FAT_FILSIG) return EBADF; return ++((tFile *) X->DeviceId)->References; } case FD32_GETATTR: { fd32_getattr_t *X = (fd32_getattr_t *) Params; if (X->Size < sizeof(fd32_getattr_t)) return EINVAL; if (((tFile *) X->FileId)->FilSig != FAT_FILSIG) return EBADF; return fat_get_attr((tFile *) X->FileId, (fd32_fs_attr_t *) X->Attr); } case FD32_SETATTR: { #ifdef FATWRITE fd32_setattr_t *X = (fd32_setattr_t *) Params; tFile *F; if (X->Size < sizeof(fd32_setattr_t)) return EINVAL; F = (tFile *) X->FileId; if (F->FilSig != FAT_FILSIG) return EBADF; #ifdef FATREMOVABLE if ((Res = fat_mediachange(F->V)) < 0) return Res; #endif return fat_set_attr(F, (fd32_fs_attr_t *) X->Attr); #else return EROFS; #endif } case FD32_REOPENDIR: { fd32_reopendir_t *X = (fd32_reopendir_t *) Params; tVolume *V; if (X->Size < sizeof(fd32_reopendir_t)) return EINVAL; V = (tVolume *) X->DeviceId; if (V->VolSig != FAT_VOLSIG) return ENODEV; #ifdef FATREMOVABLE if ((Res = fat_mediachange(V)) < 0) return Res; #endif return fat_reopendir(V, (tFindRes *) X->DtaReserved, (tFile **) &X->DirId); } case FD32_UNLINK: { #ifdef FATWRITE fd32_unlink_t *X = (fd32_unlink_t *) Params; tVolume *V; if (X->Size < sizeof(fd32_unlink_t)) return EINVAL; V = (tVolume *) X->DeviceId; if (V->VolSig != FAT_VOLSIG) return ENODEV; #ifdef FATREMOVABLE if ((Res = fat_mediachange(V)) < 0) return Res; #endif return fat_unlink(V, X->FileName, X->Flags); #else return EROFS; #endif } case FD32_RENAME: { #ifdef FATWRITE fd32_rename_t *X = (fd32_rename_t *) Params; tVolume *V; if (X->Size < sizeof(fd32_rename_t)) return EINVAL; V = (tVolume *) X->DeviceId; if (V->VolSig != FAT_VOLSIG) return ENODEV; #ifdef FATREMOVABLE if ((Res = fat_mediachange(V)) < 0) return Res; #endif return fat_rename(V, X->OldName, X->NewName); #else return EROFS; #endif } case FD32_MKDIR: { #ifdef FATWRITE fd32_mkdir_t *X = (fd32_mkdir_t *) Params; tVolume *V; if (X->Size < sizeof(fd32_mkdir_t)) return EINVAL; V = (tVolume *) X->DeviceId; if (V->VolSig != FAT_VOLSIG) return ENODEV; #ifdef FATREMOVABLE if ((Res = fat_mediachange(V)) < 0) return Res; #endif return fat_mkdir(V, X->DirName); #else return FD32_EROFS; #endif } case FD32_RMDIR: { #ifdef FATWRITE fd32_rmdir_t *X = (fd32_rmdir_t *) Params; tVolume *V; if (X->Size < sizeof(fd32_rmdir_t)) return EINVAL; V = (tVolume *) X->DeviceId; if (V->VolSig != FAT_VOLSIG) return ENODEV; #ifdef FATREMOVABLE if ((Res = fat_mediachange(V)) < 0) return Res; #endif return fat_rmdir(V, X->DirName); #else return FD32_EROFS; #endif } case FD32_MOUNT: { fd32_mount_t *X = (fd32_mount_t *) Params; if (X->Size < sizeof(fd32_mount_t)) return EINVAL; return fat_mount(X->hDev, (tVolume **) &X->FsDev); } case FD32_UNMOUNT: { fd32_unmount_t *X = (fd32_unmount_t *) Params; tVolume *V; if (X->Size < sizeof(fd32_unmount_t)) return EINVAL; V = (tVolume *) X->DeviceId; if (V->VolSig != FAT_VOLSIG) return ENODEV; #ifdef FATREMOVABLE if ((Res = fat_mediachange(V)) < 0) return Res; #endif return fat_unmount(V); } case FD32_PARTCHECK: { fd32_partcheck_t *X = (fd32_partcheck_t *) Params; if (X->Size < sizeof(fd32_partcheck_t)) return EINVAL; return fat_partcheck(X->PartId); } case FD32_GETFSINFO: { fd32_getfsinfo_t *X = (fd32_getfsinfo_t *) Params; if (X->Size < sizeof(fd32_getfsinfo_t)) return EINVAL; return fat_get_fsinfo((fd32_fs_info_t *) X->FSInfo); } case FD32_GETFSFREE: return fat_get_fsfree((fd32_getfsfree_t *) Params); } return EINVAL; }
// New style fat system custom reading extern u32 fs_dir_to_menu(const char *dir, char *sdir, u32 icolor, u32 selicolor, u32 selrcolor, u32 selbcolor, bool showhidden, bool showunknown) { int fid; p_fat_info info; u32 count; u32 i; t_win_menuitem item; if (menu_renew(&g_menu) == NULL) { return 0; } fid = freq_enter_hotzone(); count = fat_readdir(dir, sdir, &info); if (count == INVALID) { freq_leave(fid); return 0; } add_parent_to_menu(g_menu, icolor, selicolor, selrcolor, selbcolor); for (i = 0; i < count; i++) { win_menuitem_new(&item); if (!showhidden && (info[i].attr & FAT_FILEATTR_HIDDEN) > 0) { win_menuitem_free(&item); continue; } if (info[i].attr & FAT_FILEATTR_DIRECTORY) { item.data = (void *) fs_filetype_dir; buffer_copy_string(item.shortname, info[i].filename); buffer_copy_string(item.compname, info[i].longname); item.name[0] = '<'; if ((item.width = strlen(info[i].longname) + 2) > MAX_ITEM_NAME_LEN) { strncpy_s(&item.name[1], NELEMS(item.name) - 1, info[i].longname, MAX_ITEM_NAME_LEN - 5); item.name[MAX_ITEM_NAME_LEN - 4] = item.name[MAX_ITEM_NAME_LEN - 3] = item.name[MAX_ITEM_NAME_LEN - 2] = '.'; item.name[MAX_ITEM_NAME_LEN - 1] = '>'; item.name[MAX_ITEM_NAME_LEN] = 0; item.width = MAX_ITEM_NAME_LEN; } else { strncpy_s(&item.name[1], NELEMS(item.name) - 1, info[i].longname, MAX_ITEM_NAME_LEN); item.name[item.width - 1] = '>'; item.name[item.width] = 0; } } else { t_fs_filetype ft; if (info[i].filesize == 0) { win_menuitem_free(&item); continue; } ft = fs_file_get_type(info[i].longname); if (!showunknown && ft == fs_filetype_unknown) { win_menuitem_free(&item); continue; } item.data = (void *) ft; buffer_copy_string(item.shortname, info[i].filename); buffer_copy_string(item.compname, info[i].longname); filename_to_itemname(&item, info[i].longname); } item.icolor = icolor; item.selicolor = selicolor; item.selrcolor = selrcolor; item.selbcolor = selbcolor; item.selected = false; item.data2[0] = info[i].cdate; item.data2[1] = info[i].ctime; item.data2[2] = info[i].mdate; item.data2[3] = info[i].mtime; item.data3 = info[i].filesize; win_menu_add(g_menu, &item); } free(info); freq_leave(fid); return g_menu->size; }
static int umsdos_readdir_x (struct inode *dir, struct file *filp, void *dirbuf, struct umsdos_dirent *u_entry, filldir_t filldir) { struct dentry *demd; off_t start_fpos; int ret = 0; loff_t pos; umsdos_startlookup (dir); if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS && dir == pseudo_root) { /* * We don't need to simulate this pseudo directory * when umsdos_readdir_x is called for internal operation * of umsdos. This is why dirent_in_fs is tested */ /* #Specification: pseudo root / directory /DOS * When umsdos operates in pseudo root mode (C:\linux is the * linux root), it simulate a directory /DOS which points to * the real root of the file system. */ Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n")); if (filldir (dirbuf, "DOS", 3, UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO, DT_DIR) == 0) { filp->f_pos++; } goto out_end; } if (filp->f_pos < 2 || (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) { int last_f_pos = filp->f_pos; struct UMSDOS_DIR_ONCE bufk; Printk (("umsdos_readdir_x: . or .. /mn/?\n")); bufk.dirbuf = dirbuf; bufk.filldir = filldir; bufk.count = 0; ret = fat_readdir (filp, &bufk, umsdos_dir_once); if (last_f_pos > 0 && filp->f_pos > last_f_pos) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS; if (u_entry != NULL) u_entry->flags = 0; goto out_end; } Printk (("umsdos_readdir_x: normal file /mn/?\n")); /* get the EMD dentry */ demd = umsdos_get_emd_dentry(filp->f_dentry); ret = PTR_ERR(demd); if (IS_ERR(demd)) goto out_end; ret = -EIO; if (!demd->d_inode) { printk(KERN_WARNING "umsdos_readir_x: EMD file %s/%s not found\n", demd->d_parent->d_name.name, demd->d_name.name); goto out_dput; } pos = filp->f_pos; start_fpos = filp->f_pos; if (pos <= UMSDOS_SPECIAL_DIRFPOS + 1) pos = 0; ret = 0; while (pos < demd->d_inode->i_size) { off_t cur_f_pos = pos; struct dentry *dret; struct inode *inode; struct umsdos_dirent entry; struct umsdos_info info; ret = -EIO; if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0) break; if (entry.name_len == 0) continue; #ifdef UMSDOS_DEBUG_VERBOSE if (entry.flags & UMSDOS_HLINK) printk("umsdos_readdir_x: %s/%s is hardlink\n", filp->f_dentry->d_name.name, entry.name); #endif umsdos_parse (entry.name, entry.name_len, &info); info.f_pos = cur_f_pos; umsdos_manglename (&info); /* * Do a real lookup on the short name. */ dret = umsdos_covered(filp->f_dentry, info.fake.fname, info.fake.len); ret = PTR_ERR(dret); if (IS_ERR(dret)) break; /* * If the file wasn't found, remove it from the EMD. */ inode = dret->d_inode; if (!inode) goto remove_name; #ifdef UMSDOS_DEBUG_VERBOSE if (inode->u.umsdos_i.i_is_hlink) printk("umsdos_readdir_x: %s/%s already resolved, ino=%ld\n", dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino); #endif Printk (("Found %s/%s, ino=%ld, flags=%x\n", dret->d_parent->d_name.name, info.fake.fname, dret->d_inode->i_ino, entry.flags)); /* check whether to resolve a hard-link */ if ((entry.flags & UMSDOS_HLINK) && !inode->u.umsdos_i.i_is_hlink) { dret = umsdos_solve_hlink (dret); ret = PTR_ERR(dret); if (IS_ERR(dret)) break; inode = dret->d_inode; if (!inode) { printk("umsdos_readdir_x: %s/%s negative after link\n", dret->d_parent->d_name.name, dret->d_name.name); goto clean_up; } } /* #Specification: pseudo root / reading real root * The pseudo root (/linux) is logically * erased from the real root. This means that * ls /DOS, won't show "linux". This avoids * infinite recursion (/DOS/linux/DOS/linux/...) while * walking the file system. */ if (inode != pseudo_root && !(entry.flags & UMSDOS_HIDDEN)) { if (filldir (dirbuf, entry.name, entry.name_len, cur_f_pos, inode->i_ino, DT_UNKNOWN) < 0) { pos = cur_f_pos; } Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n", dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino)); if (u_entry != NULL) *u_entry = entry; dput(dret); ret = 0; break; } clean_up: dput(dret); continue; remove_name: /* #Specification: umsdos / readdir / not in MSDOS * During a readdir operation, if the file is not * in the MS-DOS directory any more, the entry is * removed from the EMD file silently. */ #ifdef UMSDOS_PARANOIA printk("umsdos_readdir_x: %s/%s out of sync, erasing\n", filp->f_dentry->d_name.name, info.entry.name); #endif ret = umsdos_delentry(filp->f_dentry, &info, S_ISDIR(info.entry.mode)); if (ret) printk(KERN_WARNING "umsdos_readdir_x: delentry %s, err=%d\n", info.entry.name, ret); goto clean_up; } /* * If the fillbuf has failed, f_pos is back to 0. * To avoid getting back into the . and .. state * (see comments at the beginning), we put back * the special offset. */ filp->f_pos = pos; if (filp->f_pos == 0) filp->f_pos = start_fpos; out_dput: dput(demd); out_end: umsdos_endlookup (dir); Printk ((KERN_DEBUG "read dir %p pos %Ld ret %d\n", dir, filp->f_pos, ret)); return ret; }