红毛樱木 发表于 2020-1-31 18:24:38

ISO 9660文件系统,有详细资料吗?

研究了两天,没找到详细的资料,大神有详细资料没?
最近想研究下ISO内文件列表。

2012jiashanni 发表于 2020-1-31 18:37:56

想通过API创建还是

红毛樱木 发表于 2020-1-31 18:46:12

2012jiashanni 发表于 2020-1-31 18:37
想通过API创建还是

解析已存在的ISO文件内部文件列表。
----------------------------
Windows有API可以创建ISO吗?

2012jiashanni 发表于 2020-1-31 18:46:52

红毛樱木 发表于 2020-1-31 18:46
解析已存在的ISO文件内部文件列表。
----------------------------
Windows有API可以创建ISO吗?
就是判断ISO是 ISO 9660还是UDF?还是想获取 ISO 9660格式的ISO里的文件内容?

红毛樱木 发表于 2020-1-31 18:53:29

2012jiashanni 发表于 2020-1-31 18:46
就是判断ISO是 ISO 9660还是UDF?还是想获取 ISO 9660格式的ISO里的文件内容?

就是解析ISO文件系统。
简单说就是想获取ISO文件里的文件列表。
比如获取A.ISO文件里的文件列表

sunsea 发表于 2020-1-31 19:13:12

本帖最后由 sunsea 于 2020-1-31 19:14 编辑

当年参考https://blog.csdn.net/goodqt/article/details/17202109这个帖子写的一个小程序,提取ISO内文件的,现在可能还对你有参考价值吧。

#include <stdio.h>
#include <tchar.h>
#include <locale.h>
#include <tchar.h>
#include <string>
#include <vector>
#include <mbstring.h>
#include <stdlib.h>

using namespace std;
#ifdef _UNICODE
typedef wstring _tstring;

#else
typedef string _tstring;

#endif



#define ATAPI_SECTOR_SIZE 2048 //一个CD扇区2048Byte
#define LBA_TO_BYTE(x) (x*ATAPI_SECTOR_SIZE)
//用法isodr.exe <iso文件> <光盘内路径> <输出路径>
//例:isodr.exe C:\abc.iso /boot/boot.sdi C:\abc.tmp
//例:isodr.exe C:\abc.iso /bootmgr C:\bootmgr //输出根目录下的bootmgr
//直接运行程序显示本帮助。

struct FILE_ITEM{
      unsigned long lba;
      string FileName;
      unsigned long size;
};

int _t_real_main(int argc, _TCHAR* argv[]);
int PraseFileSystemAndFind(FILE* isofile,unsigned long lba,FILE_ITEM &item,int depth,const vector<string> &NeedFileName,bool &isfound);

int _tmain(int argc, _TCHAR* argv[])
{
      _TCHAR *help_txt = _T("ISO文件直接读取工具\t作者:sunsea\t参考网上部分代码改编而成\n高歌酹酒,来者相候,唤我今日,长缨在手。\n\n用法isodr.exe <iso文件> <光盘内路径> <输出路径>\n例:isodr.exe C:\\abc.iso /boot/boot.sdi C:\\abc.tmp\n例:isodr.exe C:\\abc.iso /bootmgr C:\\bootmgr 输出根目录下的bootmgr\n\n直接运行程序显示本帮助。");
      setlocale(LC_ALL,"chs");

      if (argc==1) {
                _tprintf(help_txt);
      }
      if (argc>1){
                return _t_real_main(argc,argv);
      }
      return 0;
}

inline size_t seek_and_read(FILE* file,void* buf,unsigned long offest,unsigned long length){
      fseek(file,offest,SEEK_SET);
      return fread(buf,length,1,file);
}


int _t_real_main(int argc, _TCHAR* argv[]){
//这里是真正做事情的代码。
      //先检查源文件是否存在。
      _TCHAR *source_filename=argv;
      FILE * source_iso=NULL;
      FILE_ITEM myFile;//目标文件
      source_iso=_tfopen(source_filename,_T("rb"));
      if (source_iso==NULL)
      {
                _ftprintf(stderr,_T("源ISO镜像打开失败!请检查文件。"));
                return -1;
      }
      FILE *output=_tfopen(argv,_T("wb"));
      if (output==NULL){
                _ftprintf(stderr,_T("目标文件打开失败!请检查文件。"));

                return -1;
      }

      char buf_sector_1;
      /* iso的前32768字节被保留,检查CD001标志*/
      unsigned long lba = (0x8000 / 0x800); /*从0x8000的地方开始寻找.*/
      for(;;++lba)
      {
                //ISO9660最大允许整个iso 2G大小。
                if(!seek_and_read(source_iso,buf_sector_1,LBA_TO_BYTE(lba),ATAPI_SECTOR_SIZE)) { //读一个扇区
                        _ftprintf(stderr,_T("源ISO镜像读取错误!请检查文件。"));
                        return -1;
                }
                /*Identifier is always "CD001".*/
                if(buf_sector_1 != 'C' ||
                        buf_sector_1 != 'D' ||
                        buf_sector_1 != '0' ||
                        buf_sector_1 != '0' ||
                        buf_sector_1 != '1' ) /*判断CD001 不符合直接返回.*/

                {
                        _ftprintf(stderr,_T("源ISO镜像非法!"));
                        return -1;
                }
                if(buf_sector_1 == 0xff) /*Volume Descriptor Set Terminator.*/
                        return -1; /*如果这是最后一个 也返回.*/
                if(buf_sector_1 != 0x01 /*Primary Volume Descriptor.*/)
                        continue; /*不是Primary Volume Descriptor就继续*/

                /*Directory entry for the root directory.*/
                if(buf_sector_1 != 0x22 /*Msut 34.*/)
                        return -1;

                /*Location of extent (LBA) in both-endian format.*/
                lba = *(unsigned long *)(buf_sector_1 + 156 + 2);
                break; /*读LBA,跳出.*/
      }
    //分析文件名。分解出目录
      string Temp;
      vector<string> WantedFileName;
      char *token = NULL;
      char *next_token = NULL;
      char *Wanted;
      bool isfound=false;

#ifdef _UNICODE
      int need=0;
      need=wcstombs(NULL,argv,0)+1;
      Wanted = new char;
      wcstombs(Wanted,argv,need);
#else
      Wanted = new char)+1];
      strcpy(Wanted,argv);
#endif
      token=strtok_s(Wanted,"/",&next_token);
      
      while (token != NULL)
      {
                if (token != NULL)
                {
                        Temp=token;
                        WantedFileName.push_back(Temp);
                        token = strtok_s(NULL,"/", &next_token);
                        
                }
      }

      delete [] Wanted;//切分完毕
      PraseFileSystemAndFind(source_iso,lba,myFile,0,WantedFileName,isfound);
      if (!isfound){
                _ftprintf(stderr,_T("没找到你要的文件!"));
      }else{
                _tprintf(_T("找到目标文件,大小%d,LBA %d\n"),myFile.size,myFile.lba);
                fseek(source_iso,LBA_TO_BYTE(myFile.lba),SEEK_SET);
                char buffer; //按4K一块
                for (unsigned int i=0;i<=(myFile.size/4096);i++){
                        if (i==(myFile.size/4096)){
                              //最后一块
                              fread(buffer,myFile.size-i*4096,1,source_iso);
                              fwrite(buffer,myFile.size-i*4096,1,output);
                              _tprintf(_T("输出完毕。"));
                        }else{
                              fread(buffer,4096,1,source_iso);
                              fwrite(buffer,4096,1,output);
                        }
                }
      }
      fclose(output);
      fclose(source_iso);
      if (!isfound){
                _tremove(argv);
      }
      
      return 0;
}

int PraseFileSystemAndFind(FILE* isofile,unsigned long lba,FILE_ITEM &item,int depth,const vector<string> &NeedFileName,bool &isfound){
      
isfound=false;


      char SectorBuf;
      seek_and_read(isofile,SectorBuf,LBA_TO_BYTE(lba),ATAPI_SECTOR_SIZE);

   unsigned long offset = 0; /*要读的文件(夹)的信息结构的偏移.*/
   bool isDir = 0; /*是否是文件夹.*/
   bool needRead = 0; /*需不需要重新读.*/

   for(;;offset += SectorBuf /*Length of Directory Record.*/)
   {
      while(offset >= ATAPI_SECTOR_SIZE)
      {
         offset -= ATAPI_SECTOR_SIZE;
         ++lba;
         needRead = 1;
         /*Read again.*/
      } /*偏移超出这个扇区的范围就修正一下.*/
      if(needRead)
      seek_and_read(isofile,SectorBuf,LBA_TO_BYTE(lba),ATAPI_SECTOR_SIZE);
      needRead = 0;
      
      if(SectorBuf == 0x0) /*No more.*/
         break; /*大小是0说明结束了,退出.*/
      
      /*Location of extent (LBA) in both-endian format.*/
      unsigned long fileLBA = *(unsigned long *)(SectorBuf + offset + 0x2);
      if(fileLBA <= lba)
      continue; /*获取文件LBA,小于就继续吧.*/


      isDir = SectorBuf & 0x2; /*Is it a dir?*/

      unsigned long filesize = *(unsigned long *)(SectorBuf + offset + 10);

      /*Length of file identifier (file name).
       * This terminates with a ';' character
       * followed by the file ID number in ASCII coded decimal ('1').*/
      unsigned long filenameLength = SectorBuf;
      //if(!isDir) /*如果是文件就要删掉最后的";1".*/
      //   filenameLength -= 2; /*Remove ';' and '1'.*/

      char *filename =new char; /*Add 1 for '\0'.*/
      memcpy(filename,
         (const void *)(SectorBuf + offset + 33),
         filenameLength); /*把文件名复制过来.*/

      if((!isDir) && (filename == '_'))
         filename = '.';
      if((!isDir) && (filename == '.'))
         filename = '\0';
      else
         filename = '\0'; /*做一些修正.*/

      string _filename_safe = filename;
delete [] filename;

      if(!isDir)
      {

                  if(filesize != 0)
                  {
                        if (!stricmp(NeedFileName.c_str(),_filename_safe.c_str())) //找到了!
                        {
                                  item.FileName=_filename_safe;
                                  item.lba=fileLBA;
                                  item.size=filesize;
                                  isfound=true;
                                  return 1;
                        }
                  }

      }
      else
      {
                  if (!stricmp(NeedFileName.c_str(),_filename_safe.c_str()))
                        PraseFileSystemAndFind(isofile,fileLBA,item,depth+1,NeedFileName,isfound); /*对的就递归.*/

      }
   }
         

          return 0;
}

编译结果就不放了,VS2005下编译通过,注意,输出的LBA是2048字节大扇区式的LBA。

红毛樱木 发表于 2020-1-31 19:14:28

sunsea 发表于 2020-1-31 19:13
当年参考https://blog.csdn.net/goodqt/article/details/17202109这个帖子写的一个小程序,提取ISO内文件的 ...

我也是看这里的,这里不全

sunsea 发表于 2020-1-31 19:16:49

红毛樱木 发表于 2020-1-31 19:14
我也是看这里的,这里不全
能按路径找到文件应该就能列出所有文件吧?或许可以试试能不能改造下这个程序列出所有文件和它们的LBA和长度,而且ISO9660还有个很棒的特点——所有文件都是连续的。

https://blog.csdn.net/perry_peng/article/details/7698673另外这里似乎还有个Python程序也能有帮助。

红毛樱木 发表于 2020-2-6 15:39:59

决定放弃了,ISO文件的文件系统太多了。
页: [1]
查看完整版本: ISO 9660文件系统,有详细资料吗?