从上面的代码里可以看到调用函数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,ReqAttr);
#014 }
接着来分析创建一个FAT入口函数FATAddEntry:
#001 static NTSTATUS
#002 FATAddEntry(
#003 IN PDEVICE_EXTENSION DeviceExt,
#005 IN PVFATFCB* Fcb,
#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",&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
#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,&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,&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,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,needTilde,needLong);
#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,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,&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,size,TRUE,
#270 &Context,(PVOID*)&pFatEntry);
#271 RtlCopyMemory(pFatEntry,size);
#272 CcSetDirtyPinnedData(Context,NULL);
#273 CcUnpinData(Context);
#274 FileOffset.u.LowPart += size;
#275 CcPinRead(ParentFcb->FileObject,
#276 nbSlots * sizeof(FAT_DIR_ENTRY) - size,
#277 TRUE,(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,sizeof(FAT_DIR_ENTRY));
#283 }
#284 CcSetDirtyPinnedData(Context,NULL);
#285 CcUnpinData(Context);
#286
#287 /* FIXME: check status */
#288 vfatMakeFCBFromDirEntry(DeviceExt,&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,DeviceExt->FatInfo.BytesPerCluster,
#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,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}
原文链接:https://www.f2er.com/react/308397.html