reactos操作系统实现(127)
从上面的代码里可以看到调用函数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
判断文件名称是否符合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,&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);
设置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,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} (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |