现在的位置: 首页 > 综合 > 正文

reactos操作系统实现(127)

2013年10月13日 ⁄ 综合 ⁄ 共 14018字 ⁄ 字号 评论关闭

 从上面的代码里可以看到调用函数VfatAddEntry来添加文件或目录的入口,其实现的代码如下:

#001  NTSTATUS

#002  VfatAddEntry(

#003      IN
PDEVICE_EXTENSION DeviceExt,

#004      IN PUNICODE_STRING NameU,

#005      IN PVFATFCB *Fcb,

#006      IN PVFATFCB ParentFcb,

#007      IN ULONG
RequestedOptions,

#008      IN UCHAR ReqAttr)

#009  {

 

这里判断是使用扩展的FAT16或者FAT32

#010      if (DeviceExt->Flags
& VCB_IS_FATX)

#011          return
FATXAddEntry(DeviceExt, NameU, Fcb, ParentFcb, RequestedOptions, ReqAttr);

#012      else

 

这里使用原来的FAT16或者FAT32

#013          return
FATAddEntry(DeviceExt, NameU, Fcb, ParentFcb, RequestedOptions, ReqAttr);

#014  }

 

接着来分析创建一个FAT入口函数FATAddEntry

#001  static NTSTATUS

#002  FATAddEntry(

#003      IN PDEVICE_EXTENSION
DeviceExt,

#004      IN PUNICODE_STRING NameU,

#005      IN PVFATFCB* Fcb,

#006      IN PVFATFCB ParentFcb,

#007      IN ULONG
RequestedOptions,

#008      IN UCHAR ReqAttr)

#009  {

#010      PVOID Context = NULL;

#011      PFAT_DIR_ENTRY
pFatEntry;

#012      slot *pSlots;

#013      USHORT nbSlots = 0, j,
posCar;

#014      PUCHAR Buffer;

#015      BOOLEAN needTilde =
FALSE, needLong = FALSE;

#016      BOOLEAN lCaseBase =
FALSE, uCaseBase, lCaseExt = FALSE, uCaseExt;

#017      ULONG CurrentCluster;

#018      LARGE_INTEGER
SystemTime, FileOffset;

#019      NTSTATUS Status =
STATUS_SUCCESS;

#020      ULONG size;

#021      long i;

#022 

#023      OEM_STRING NameA;

#024      CHAR aName[13];

#025      BOOLEAN IsNameLegal;

#026      BOOLEAN SpacesFound;

#027 

#028      VFAT_DIRENTRY_CONTEXT
DirContext;

#029      WCHAR
LongNameBuffer[LONGNAME_MAX_LENGTH + 1];

#030      WCHAR
ShortNameBuffer[13];

#031 

#032      DPRINT("addEntry:
Name='%wZ', Dir='%wZ'/n", NameU, &ParentFcb->PathNameU);

#033 

#034      DirContext.LongNameU =
*NameU;

#035 

#036      /* nb of entry needed
for long name+normal entry */

 

计算一个FAT入口的占用内存大小。

#037      nbSlots =
(DirContext.LongNameU.Length / sizeof(WCHAR) + 12) / 13 + 1;

#038      DPRINT("NameLen=
%d, nbSlots =%d/n", DirContext.LongNameU.Length / sizeof(WCHAR), nbSlots);

 

分配FAT的入口内存。

#039      Buffer =
ExAllocatePoolWithTag(NonPagedPool, (nbSlots - 1) * sizeof(FAT_DIR_ENTRY),
TAG_VFAT);

#040      if (Buffer == NULL)

#041      {

#042          return
STATUS_INSUFFICIENT_RESOURCES;

#043      }

#044      RtlZeroMemory(Buffer,
(nbSlots - 1) * sizeof(FAT_DIR_ENTRY));

#045      pSlots = (slot *)
Buffer;

#046 

#047      NameA.Buffer = aName;

#048      NameA.Length = 0;

#049      NameA.MaximumLength =
sizeof(aName);

#050 

#051     
DirContext.ShortNameU.Buffer = ShortNameBuffer;

#052     
DirContext.ShortNameU.Length = 0;

#053      DirContext.ShortNameU.MaximumLength
= sizeof(ShortNameBuffer);

#054 

#055     
RtlZeroMemory(&DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY));

#056 

 

判断文件名称是否符合DOS里的8.3的文件命名格式。

#057      IsNameLegal =
RtlIsNameLegalDOS8Dot3(&DirContext.LongNameU, &NameA, &SpacesFound);

#058 

#059      if (!IsNameLegal ||
SpacesFound)

#060      {

 

如果是非法的文件名称,或者包括有空格,就进入下面的处理。

#061         
GENERATE_NAME_CONTEXT NameContext;

#062         
VFAT_DIRENTRY_CONTEXT SearchContext;

#063          WCHAR
ShortSearchName[13];

#064          needTilde = TRUE;

#065          needLong = TRUE;

#066         
RtlZeroMemory(&NameContext, sizeof(GENERATE_NAME_CONTEXT));

#067         
SearchContext.LongNameU.Buffer = LongNameBuffer;

#068         
SearchContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);

#069         
SearchContext.ShortNameU.Buffer = ShortSearchName;

#070         
SearchContext.ShortNameU.MaximumLength = sizeof(ShortSearchName);

#071 

 

尝试100次来分配新的文件名称,并找新分配的文件名是否已经存。

#072          for (i = 0; i <
100; i++)

#073          {

#074             
RtlGenerate8dot3Name(&DirContext.LongNameU, FALSE, &NameContext,
&DirContext.ShortNameU);

#075             
DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length /
sizeof(WCHAR)] = 0;

#076                                          
SearchContext.DirIndex = 0;

 

查找新分配的文件是否存在。

#077              Status =
FindFile(DeviceExt, ParentFcb, &DirContext.ShortNameU, &SearchContext,
TRUE);

#078              if (!NT_SUCCESS(Status))

#079              {

#080                  break;

#081              }

#082          }

 

尝试100次分配新的文件名称都失败,就直接返回创建文件失败。

#083          if (i == 100) /*
FIXME : what to do after this ? */

#084          {

#085             
ExFreePoolWithTag(Buffer, TAG_VFAT);

#086              return
STATUS_UNSUCCESSFUL;

#087          }

 

这里就已经重新分配文件成功了,保存起来在后面使用。

#088          IsNameLegal =
RtlIsNameLegalDOS8Dot3(&DirContext.ShortNameU, &NameA,
&SpacesFound);

#089         
aName[NameA.Length]=0;

#090      }

#091      else

#092      {

#093          aName[NameA.Length]
= 0;

 

检查文件名称是否包括点分隔符。

#094          for (posCar = 0;
posCar < DirContext.LongNameU.Length / sizeof(WCHAR); posCar++)

#095          {

#096              if
(DirContext.LongNameU.Buffer[posCar] == L'.')

#097              {

#098                  break;

#099              }

#100          }

#101          /* check if the name
and the extension contains upper case characters */

 

检查文件名称和扩展名称是否同为小写。

#102         
RtlDowncaseUnicodeString(&DirContext.ShortNameU,
&DirContext.LongNameU, FALSE);

#103         
DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length /
sizeof(WCHAR)] = 0;

#104          uCaseBase =
wcsncmp(DirContext.LongNameU.Buffer,

#105                             
DirContext.ShortNameU.Buffer, posCar) ? TRUE : FALSE;

#106          if (posCar <
DirContext.LongNameU.Length/sizeof(WCHAR))

#107          {

#108              i =
DirContext.LongNameU.Length / sizeof(WCHAR) - posCar;

#109              uCaseExt =
wcsncmp(DirContext.LongNameU.Buffer + posCar,

#110                                
DirContext.ShortNameU.Buffer + posCar, i) ? TRUE : FALSE;

#111          }

#112          else

#113          {

#114              uCaseExt =
FALSE;

#115          }

#116          /* check if the name
and the extension contains lower case characters */

 

检查文件名称和扩展名称是否同为大写。

#117         
RtlUpcaseUnicodeString(&DirContext.ShortNameU,
&DirContext.LongNameU, FALSE);

#118         
DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length /
sizeof(WCHAR)] = 0;

#119          lCaseBase =
wcsncmp(DirContext.LongNameU.Buffer,

#120                             
DirContext.ShortNameU.Buffer, posCar) ? TRUE : FALSE;

#121          if (posCar <
DirContext.LongNameU.Length / sizeof(WCHAR))

#122          {

#123              i =
DirContext.LongNameU.Length / sizeof(WCHAR) - posCar;

#124              lCaseExt =
wcsncmp(DirContext.LongNameU.Buffer + posCar,

#125                                
DirContext.ShortNameU.Buffer + posCar, i) ? TRUE : FALSE;

#126          }

#127          else

#128          {

#129              lCaseExt =
FALSE;

#130          }

#131          if ((lCaseBase
&& uCaseBase) || (lCaseExt && uCaseExt))

#132          {

#133              needLong = TRUE;

#134          }

#135      }

#136      DPRINT("'%s',
'%wZ', needTilde=%d, needLong=%d/n",

#137             aName,
&DirContext.LongNameU, needTilde, needLong);

 

设置FAT入口的文件名称。

#138     
memset(DirContext.DirEntry.Fat.ShortName, ' ', 11);

#139      for (i = 0; i < 8
&& aName[i] && aName[i] != '.'; i++)

#140      {

#141         
DirContext.DirEntry.Fat.Filename[i] = aName[i];

#142      }

#143      if (aName[i] == '.')

#144      {

#145          i++;

#146          for (j = 0; j < 3
&& aName[i]; j++, i++)

#147          {

#148             
DirContext.DirEntry.Fat.Ext[j] = aName[i];

#149          }

#150      }

#151      if
(DirContext.DirEntry.Fat.Filename[0] == 0xe5)

#152      {

#153         
DirContext.DirEntry.Fat.Filename[0] = 0x05;

#154      }

#155 

 

如果需要长文件名称。

#156      if (needLong)

#157      {

#158         
RtlCopyMemory(LongNameBuffer, DirContext.LongNameU.Buffer,
DirContext.LongNameU.Length);

#159         
DirContext.LongNameU.Buffer = LongNameBuffer;

#160         
DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);

#161         
DirContext.LongNameU.Buffer[DirContext.LongNameU.Length / sizeof(WCHAR)]
= 0;

#162         
memset(DirContext.LongNameU.Buffer + DirContext.LongNameU.Length /
sizeof(WCHAR) + 1, 0xff,

#163                 DirContext.LongNameU.MaximumLength
- DirContext.LongNameU.Length - sizeof(WCHAR));

#164      }

#165      else

#166      {

 

这里是使用短文件名称。

#167          nbSlots = 1;

#168          if (lCaseBase)

#169          {

#170             
DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_BASE;

#171          }

#172          if (lCaseExt)

#173          {

#174             
DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_EXT;

#175          }

#176      }

#177 

#178      DPRINT ("dos
name=%11.11s/n", DirContext.DirEntry.Fat.Filename);

#179 

#180      /* set attributes */

 

设置FAT的属性。

#181     
DirContext.DirEntry.Fat.Attrib = ReqAttr;

#182      if (RequestedOptions
& FILE_DIRECTORY_FILE)

#183      {

#184         
DirContext.DirEntry.Fat.Attrib |= FILE_ATTRIBUTE_DIRECTORY;

#185      }

#186      /* set dates and times
*/

 

设置FAT创建的系统日期和时间。

#187     
KeQuerySystemTime(&SystemTime);

#188      FsdSystemTimeToDosDateTime(DeviceExt,
&SystemTime, &DirContext.DirEntry.Fat.CreationDate,

#189                                
&DirContext.DirEntry.Fat.CreationTime);

#190     
DirContext.DirEntry.Fat.UpdateDate =
DirContext.DirEntry.Fat.CreationDate;

#191      DirContext.DirEntry.Fat.UpdateTime
= DirContext.DirEntry.Fat.CreationTime;

#192     
DirContext.DirEntry.Fat.AccessDate =
DirContext.DirEntry.Fat.CreationDate;

#193 

#194      if (needLong)

#195      {

#196          /* calculate
checksum for 8.3 name */

#197          for
(pSlots[0].alias_checksum = 0, i = 0; i < 11; i++)

#198          {

#199             
pSlots[0].alias_checksum = (((pSlots[0].alias_checksum & 1) <<
7

#200                                       |
((pSlots[0].alias_checksum & 0xfe) >> 1))

#201                                       +
DirContext.DirEntry.Fat.ShortName[i]);

#202          }

#203          /* construct slots
and entry */

 

构造所有入口。

#204          for (i = nbSlots -
2; i >= 0; i--)

#205          {

#206             
DPRINT("construct slot %d/n", i);

#207              pSlots[i].attr =
0xf;

#208              if (i)

#209              {

#210                  pSlots[i].id
= (unsigned char)(nbSlots - i - 1);

#211              }

#212              else

#213              {

#214                  pSlots[i].id
= (unsigned char)(nbSlots - i - 1 + 0x40);

#215              }

#216             
pSlots[i].alias_checksum = pSlots[0].alias_checksum;

#217             
RtlCopyMemory(pSlots[i].name0_4, DirContext.LongNameU.Buffer + (nbSlots
- i - 2) * 13, 10);

#218             
RtlCopyMemory(pSlots[i].name5_10, DirContext.LongNameU.Buffer + (nbSlots
- i - 2) * 13 + 5, 12);

#219              RtlCopyMemory(pSlots[i].name11_12,
DirContext.LongNameU.Buffer + (nbSlots - i - 2) * 13 + 11, 4);

#220          }

#221      }

#222      /* try to find nbSlots
contiguous entries frees in directory */

 

在这个目录里找到空闲位置。

#223      if
(!vfatFindDirSpace(DeviceExt, ParentFcb, nbSlots, &DirContext.StartIndex))

#224      {

#225         
ExFreePoolWithTag(Buffer, TAG_VFAT);

#226          return
STATUS_DISK_FULL;

#227      }

#228      DirContext.DirIndex =
DirContext.StartIndex + nbSlots - 1;

#229      if (RequestedOptions
& FILE_DIRECTORY_FILE)

#230      {

#231          CurrentCluster = 0;

#232          Status =
NextCluster(DeviceExt, 0, &CurrentCluster, TRUE);

#233          if (CurrentCluster
== 0xffffffff || !NT_SUCCESS(Status))

#234          {

#235              ExFreePoolWithTag(Buffer,
TAG_VFAT);

#236              if
(!NT_SUCCESS(Status))

#237              {

#238                  return
Status;

#239              }

#240              return
STATUS_DISK_FULL;

#241          }

#242          if
(DeviceExt->FatInfo.FatType == FAT32)

#243          {

#244             
DirContext.DirEntry.Fat.FirstClusterHigh = (unsigned
short)(CurrentCluster >> 16);

#245          }

#246         
DirContext.DirEntry.Fat.FirstCluster = (unsigned short)CurrentCluster;

#247      }

#248 

#249      i = DeviceExt->FatInfo.BytesPerCluster
/ sizeof(FAT_DIR_ENTRY);

#250      FileOffset.u.HighPart =
0;

#251      FileOffset.u.LowPart =
DirContext.StartIndex * sizeof(FAT_DIR_ENTRY);

#252      if
(DirContext.StartIndex / i == DirContext.DirIndex / i)

#253      {

 

一个簇的处理。

#254          /* one cluster */

#255         
CcPinRead(ParentFcb->FileObject, &FileOffset, nbSlots *
sizeof(FAT_DIR_ENTRY),

#256                    TRUE,
&Context, (PVOID*)&pFatEntry);

#257          if (nbSlots > 1)

#258          {

#259              RtlCopyMemory(pFatEntry,
Buffer, (nbSlots - 1) * sizeof(FAT_DIR_ENTRY));

#260          }

#261         
RtlCopyMemory(pFatEntry + (nbSlots - 1), &DirContext.DirEntry.Fat,
sizeof(FAT_DIR_ENTRY));

#262      }

#263      else

#264      {

 

二个簇的处理。

#265          /* two clusters */

#266          size =
DeviceExt->FatInfo.BytesPerCluster -

#267                
(DirContext.StartIndex * sizeof(FAT_DIR_ENTRY)) %
DeviceExt->FatInfo.BytesPerCluster;

#268          i = size /
sizeof(FAT_DIR_ENTRY);

#269          CcPinRead(ParentFcb->FileObject,
&FileOffset, size, TRUE,

#270                   
&Context, (PVOID*)&pFatEntry);

#271         
RtlCopyMemory(pFatEntry, Buffer, size);

#272         
CcSetDirtyPinnedData(Context, NULL);

#273         
CcUnpinData(Context);

#274          FileOffset.u.LowPart += size;

#275         
CcPinRead(ParentFcb->FileObject, &FileOffset,

#276                    nbSlots *
sizeof(FAT_DIR_ENTRY) - size,

#277                    TRUE,
&Context, (PVOID*)&pFatEntry);

#278          if (nbSlots - 1 >
i)

#279          {

#280             
RtlCopyMemory(pFatEntry, (PVOID)(Buffer + size), (nbSlots - 1 - i) *
sizeof(FAT_DIR_ENTRY));

#281          }

#282         
RtlCopyMemory(pFatEntry + nbSlots - 1 - i, &DirContext.DirEntry.Fat,
sizeof(FAT_DIR_ENTRY));

#283      }

#284     
CcSetDirtyPinnedData(Context, NULL);

#285      CcUnpinData(Context);

#286 

#287      /* FIXME: check status
*/

#288     
vfatMakeFCBFromDirEntry(DeviceExt, ParentFcb, &DirContext, Fcb);

#289 

#290      DPRINT("new :
entry=%11.11s/n", (*Fcb)->entry.Fat.Filename);

#291      DPRINT("new :
entry=%11.11s/n", DirContext.DirEntry.Fat.Filename);

#292 

 

检查是否目录文件。

#293      if (RequestedOptions
& FILE_DIRECTORY_FILE)

#294      {

#295          FileOffset.QuadPart
= 0;

#296         
CcPinRead((*Fcb)->FileObject, &FileOffset,
DeviceExt->FatInfo.BytesPerCluster, TRUE,

#297                   
&Context, (PVOID*)&pFatEntry);

#298          /* clear the new
directory cluster */

#299         
RtlZeroMemory(pFatEntry, DeviceExt->FatInfo.BytesPerCluster);

 

在文件目录里创建缺省目录'.' '..'

#300          /* create '.' and
'..' */

#301         
RtlCopyMemory(&pFatEntry[0].Attrib, &DirContext.DirEntry.Fat.Attrib,
sizeof(FAT_DIR_ENTRY) - 11);

#302         
RtlCopyMemory(pFatEntry[0].ShortName, ".          ", 11);

#303         
RtlCopyMemory(&pFatEntry[1].Attrib,
&DirContext.DirEntry.Fat.Attrib, sizeof(FAT_DIR_ENTRY) - 11);

#304          RtlCopyMemory(pFatEntry[1].ShortName,
"..         ", 11);

#305         
pFatEntry[1].FirstCluster = ParentFcb->entry.Fat.FirstCluster;

#306         
pFatEntry[1].FirstClusterHigh =
ParentFcb->entry.Fat.FirstClusterHigh;

 

如果这里根目录,就设置父目录为空,不能再往上查看。

#307          if
(vfatFCBIsRoot(ParentFcb))

#308          {

#309             
pFatEntry[1].FirstCluster = 0;

#310             
pFatEntry[1].FirstClusterHigh = 0;

#311          }

#312         
CcSetDirtyPinnedData(Context, NULL);

#313         
CcUnpinData(Context);

#314      }

#315     
ExFreePoolWithTag(Buffer, TAG_VFAT);

#316      DPRINT("addentry
ok/n");

#317      return STATUS_SUCCESS;

#318  }

抱歉!评论已关闭.