从上面的代码里可以看到调用函数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 }