01530329f47126aacef9198a8ae0885377e43c62
[reactos.git] / reactos / drivers / fs / vfat / dirwr.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: services/fs/vfat/dirwr.c
5 * PURPOSE: VFAT Filesystem : write in directory
6
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ddk/ntddk.h>
12 #include <ctype.h>
13 #include <wchar.h>
14 #include <internal/string.h>
15
16 #define NDEBUG
17 #include <internal/debug.h>
18
19 #include "vfat.h"
20
21 NTSTATUS updEntry(PDEVICE_EXTENSION DeviceExt,PFILE_OBJECT pFileObject)
22 /*
23 update an existing FAT entry
24 */
25 {
26 WCHAR DirName[MAX_PATH],*FileName,*PathFileName;
27 VFATFCB FileFcb;
28 ULONG Sector=0,Entry=0;
29 PUCHAR Buffer;
30 FATDirEntry * pEntries;
31 NTSTATUS status;
32 FILE_OBJECT FileObject;
33 PVFATCCB pDirCcb;
34 PVFATFCB pDirFcb,pFcb;
35 short i,posCar,NameLen;
36 PathFileName=pFileObject->FileName.Buffer;
37 pFcb=((PVFATCCB)pFileObject->FsContext2)->pFcb;
38 //find last \ in PathFileName
39 posCar=-1;
40 for(i=0;PathFileName[i];i++)
41 if(PathFileName[i]=='\\')posCar=i;
42 if(posCar==-1)
43 return STATUS_UNSUCCESSFUL;
44 FileName=&PathFileName[posCar+1];
45 for(NameLen=0;FileName[NameLen];NameLen++);
46 // extract directory name from pathname
47 memcpy(DirName,PathFileName,posCar*sizeof(WCHAR));
48 DirName[posCar]=0;
49 if(FileName[0]==0 && DirName[0]==0)
50 return STATUS_SUCCESS;//root : nothing to do ?
51 memset(&FileObject,0,sizeof(FILE_OBJECT));
52 DPRINT("open directory %S for update of entry %S\n",DirName,FileName);
53 status=FsdOpenFile(DeviceExt,&FileObject,DirName);
54 pDirCcb=(PVFATCCB)FileObject.FsContext2;
55 assert(pDirCcb);
56 pDirFcb=pDirCcb->pFcb;
57 assert(pDirFcb);
58 FileFcb.ObjectName=&FileFcb.PathName[0];
59 status=FindFile(DeviceExt,&FileFcb,pDirFcb,FileName,&Sector,&Entry);
60 if(NT_SUCCESS(status))
61 {
62 Buffer=ExAllocatePool(NonPagedPool,BLOCKSIZE);
63 DPRINT("update entry: sector %d, entry %d\n",Sector,Entry);
64 VFATReadSectors(DeviceExt->StorageDevice,Sector,1,Buffer);
65 pEntries=(FATDirEntry *)Buffer;
66 memcpy(&pEntries[Entry],&pFcb->entry,sizeof(FATDirEntry));
67 VFATWriteSectors(DeviceExt->StorageDevice,Sector,1,Buffer);
68 ExFreePool(Buffer);
69 }
70 FsdCloseFile(DeviceExt,&FileObject);
71 return status;
72 }
73
74 NTSTATUS addEntry(PDEVICE_EXTENSION DeviceExt
75 ,PFILE_OBJECT pFileObject,ULONG RequestedOptions,UCHAR ReqAttr)
76 /*
77 create a new FAT entry
78 */
79 {
80 WCHAR DirName[MAX_PATH],*FileName,*PathFileName;
81 VFATFCB DirFcb,FileFcb;
82 FATDirEntry FatEntry;
83 NTSTATUS status;
84 FILE_OBJECT FileObject;
85 FATDirEntry *pEntry;
86 slot *pSlots;
87 ULONG LengthRead,Offset;
88 short nbSlots=0,nbFree=0,i,j,posCar,NameLen;
89 PUCHAR Buffer,Buffer2;
90 BOOLEAN needTilde=FALSE,needLong=FALSE;
91 PVFATFCB newFCB;
92 PVFATCCB newCCB;
93 ULONG CurrentCluster;
94 KIRQL oldIrql;
95
96 PathFileName=pFileObject->FileName.Buffer;
97 DPRINT("addEntry: Pathname=%S\n",PathFileName);
98 //find last \ in PathFileName
99 posCar=-1;
100 for(i=0;PathFileName[i];i++)
101 if(PathFileName[i]=='\\')posCar=i;
102 if(posCar==-1)
103 return STATUS_UNSUCCESSFUL;
104 FileName=&PathFileName[posCar+1];
105 for(NameLen=0;FileName[NameLen];NameLen++);
106 // extract directory name from pathname
107 memcpy(DirName,PathFileName,posCar*sizeof(WCHAR));
108 DirName[posCar]=0;
109 // open parent directory
110 memset(&FileObject,0,sizeof(FILE_OBJECT));
111 status=FsdOpenFile(DeviceExt,&FileObject,DirName);
112 nbSlots=(NameLen+12)/13+1;//nb of entry needed for long name+normal entry
113 DPRINT("NameLen= %d, nbSlots =%d\n",NameLen,nbSlots);
114 Buffer=ExAllocatePool(NonPagedPool,(nbSlots+1)*sizeof(FATDirEntry));
115 memset(Buffer,0,(nbSlots+1)*sizeof(FATDirEntry));
116 pEntry=(FATDirEntry *)(Buffer+(nbSlots-1)*sizeof(FATDirEntry));
117 pSlots=(slot *)Buffer;
118 // create 8.3 name
119 needTilde=FALSE;
120 // find last point in name
121 posCar=0;
122 for(i=0;FileName[i];i++)
123 if(FileName[i]=='.')posCar=i;
124 if(!posCar) posCar=i;
125 if(posCar>8) needTilde=TRUE;
126 //copy 8 characters max
127 memset(pEntry,' ',11);
128 for(i=0,j=0;j<8 && i<posCar;i++)
129 {
130 //FIXME : is there other characters to ignore ?
131 if( FileName[i]!='.'
132 && FileName[i]!=' '
133 && FileName[i]!='+'
134 && FileName[i]!=','
135 && FileName[i]!=';'
136 && FileName[i]!='='
137 && FileName[i]!='['
138 && FileName[i]!=']'
139 )
140 pEntry->Filename[j++]=toupper((char) FileName[i]);
141 else
142 needTilde=TRUE;
143 }
144 //copy extension
145 if(FileName[posCar])
146 for(j=0,i=posCar+1;FileName[i] && i<posCar+4;i++)
147 {
148 pEntry->Ext[j++]=toupper((char)( FileName[i] &0x7F));
149 }
150 if(FileName[i])
151 needTilde=TRUE;
152 //find good value for tilde
153 if(needTilde)
154 {
155 needLong=TRUE;
156 DPRINT("searching a good value for tilde\n");
157 for(i=0;i<6;i++)
158 DirName[i]=pEntry->Filename[i];
159 for(i=0;i<3;i++)
160 DirName[i+8]=pEntry->Ext[i];
161 //try first with xxxxxx~y.zzz
162 DirName[6]='~';
163 pEntry->Filename[6]='~';
164 DirName[8]='.';
165 DirName[12]=0;
166 for(i=1;i<9;i++)
167 {
168 DirName[7]='0'+i;
169 pEntry->Filename[7]='0'+i;
170 status=FindFile(DeviceExt,&FileFcb
171 ,&DirFcb,DirName,NULL,NULL);
172 if(status!=STATUS_SUCCESS)break;
173 }
174 //try second with xxxxx~yy.zzz
175 if(i==10)
176 {
177 DirName[5]='~';
178 for( ;i<99;i++)
179 {
180 DirName[7]='0'+i;
181 pEntry->Filename[7]='0'+i;
182 status=FindFile(DeviceExt,&FileFcb
183 ,&DirFcb,DirName,NULL,NULL);
184 if(status!=STATUS_SUCCESS)break;
185 }
186 }
187 if(i==100)//FIXME : what to do after 99 tilde ?
188 {
189 FsdCloseFile(DeviceExt,&FileObject);
190 ExFreePool(Buffer);
191 return STATUS_UNSUCCESSFUL;
192 }
193 }
194 else
195 {
196 DPRINT("check if long name entry needed, needlong=%d\n",needLong);
197 for(i=0;i<posCar;i++)
198 if((USHORT)pEntry->Filename[i]!=FileName[i])
199 {
200 DPRINT("i=%d,%d,%d\n",i,pEntry->Filename[i],FileName[i]);
201 needLong=TRUE;
202 }
203 if(FileName[i])
204 {
205 i++;//jump on point char
206 for(j=0,i=posCar+1;FileName[i] && i<posCar+4;i++)
207 if((USHORT)pEntry->Ext[j++]!= FileName[i])
208 {
209 DPRINT("i=%d,j=%d,%d,%d\n",i,j,pEntry->Filename[i],FileName[i]);
210 needLong=TRUE;
211 }
212 }
213 }
214 if(needLong==FALSE)
215 {
216 nbSlots=1;
217 memcpy(Buffer,pEntry,sizeof(FATDirEntry));
218 memset(pEntry,0,sizeof(FATDirEntry));
219 pEntry=(FATDirEntry *)Buffer;
220 }
221 else
222 {
223 memset(DirName,0xff,sizeof(DirName));
224 memcpy(DirName,FileName,NameLen*sizeof(WCHAR));
225 DirName[NameLen]=0;
226 }
227 DPRINT("dos name=%11.11s\n",pEntry->Filename);
228 //FIXME : set attributes, dates, times
229 pEntry->Attrib=ReqAttr;
230
231 if(RequestedOptions&FILE_DIRECTORY_FILE)
232 pEntry->Attrib |= FILE_ATTRIBUTE_DIRECTORY;
233 pEntry->CreationDate=0x21;
234 pEntry->UpdateDate=0x21;
235 // calculate checksum for 8.3 name
236 for(pSlots[0].alias_checksum=i=0;i<11;i++)
237 {
238 pSlots[0].alias_checksum=(((pSlots[0].alias_checksum&1)<<7
239 |((pSlots[0].alias_checksum&0xfe)>>1))
240 +pEntry->Filename[i]);
241 }
242 //construct slots and entry
243 for(i=nbSlots-2;i>=0;i--)
244 {
245 DPRINT("construct slot %d\n",i);
246 pSlots[i].attr=0xf;
247 if (i)
248 pSlots[i].id=nbSlots-i-1;
249 else
250 pSlots[i].id=nbSlots-i-1+0x40;
251 pSlots[i].alias_checksum=pSlots[0].alias_checksum;
252 //FIXME pSlots[i].start=;
253 memcpy(pSlots[i].name0_4 ,FileName+(nbSlots-i-2)*13
254 ,5*sizeof(WCHAR));
255 memcpy(pSlots[i].name5_10 ,FileName+(nbSlots-i-2)*13+5
256 ,6*sizeof(WCHAR));
257 memcpy(pSlots[i].name11_12,FileName+(nbSlots-i-2)*13+11
258 ,2*sizeof(WCHAR));
259 }
260 //try to find nbSlots contiguous entries frees in directory
261 for(i=0,status=STATUS_SUCCESS;status==STATUS_SUCCESS;i++)
262 {
263 status=FsdReadFile(DeviceExt,&FileObject,&FatEntry
264 ,sizeof(FATDirEntry),i*sizeof(FATDirEntry),&LengthRead);
265 if(IsLastEntry(&FatEntry,0))
266 break;
267 if(IsDeletedEntry(&FatEntry,0)) nbFree++;
268 else nbFree=0;
269 if (nbFree==nbSlots) break;
270 }
271 DPRINT("NbFree %d, entry number %d\n",nbFree,i);
272 if(RequestedOptions&FILE_DIRECTORY_FILE)
273 {
274 CurrentCluster=GetNextWriteCluster(DeviceExt,0);
275 // zero the cluster
276 Buffer2=ExAllocatePool(NonPagedPool,DeviceExt->BytesPerCluster);
277 memset(Buffer2,0,DeviceExt->BytesPerCluster);
278 VFATWriteCluster(DeviceExt,Buffer2,CurrentCluster);
279 ExFreePool(Buffer2);
280 if (DeviceExt->FatType == FAT32)
281 {
282 pEntry->FirstClusterHigh=CurrentCluster>>16;
283 pEntry->FirstCluster=CurrentCluster;
284 }
285 else
286 pEntry->FirstCluster=CurrentCluster;
287 }
288 if(nbFree==nbSlots)
289 {//use old slots
290 Offset=(i-nbSlots+1)*sizeof(FATDirEntry);
291 status=FsdWriteFile(DeviceExt,&FileObject,Buffer
292 ,sizeof(FATDirEntry)*nbSlots,Offset);
293 }
294 else
295 {//write at end of directory
296 Offset=(i-nbFree)*sizeof(FATDirEntry);
297 status=FsdWriteFile(DeviceExt,&FileObject,Buffer
298 ,sizeof(FATDirEntry)*(nbSlots+1),Offset);
299 }
300 DPRINT("write entry offset %d status=%x\n",Offset,status);
301 newCCB = ExAllocatePool(NonPagedPool,sizeof(VFATCCB));
302 newFCB = ExAllocatePool(NonPagedPool,sizeof(VFATFCB));
303 memset(newCCB,0,sizeof(VFATCCB));
304 memset(newFCB,0,sizeof(VFATFCB));
305 newCCB->pFcb=newFCB;
306 newCCB->PtrFileObject=pFileObject;
307 newFCB->RefCount++;
308
309 /*
310 * FIXME : initialize all fields in FCB and CCB
311 */
312 KeAcquireSpinLock(&DeviceExt->FcbListLock, &oldIrql);
313 InsertTailList(&DeviceExt->FcbListHead, &newFCB->FcbListEntry);
314 KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
315
316
317 memcpy(&newFCB->entry,pEntry,sizeof(FATDirEntry));
318 DPRINT("new : entry=%11.11s\n",newFCB->entry.Filename);
319 DPRINT("new : entry=%11.11s\n",pEntry->Filename);
320 vfat_wcsncpy(newFCB->PathName,PathFileName,MAX_PATH);
321 newFCB->ObjectName=newFCB->PathName+(PathFileName-FileName);
322 newFCB->pDevExt=DeviceExt;
323 pFileObject->FsContext =(PVOID) &newFCB->NTRequiredFCB;
324 pFileObject->FsContext2 = newCCB;
325 if(RequestedOptions&FILE_DIRECTORY_FILE)
326 {
327 // create . and ..
328 memcpy(pEntry->Filename,". ",11);
329 status=FsdWriteFile(DeviceExt,pFileObject,pEntry
330 ,sizeof(FATDirEntry),0L);
331 pEntry->FirstCluster
332 =((VFATCCB *)(FileObject.FsContext2))->pFcb->entry.FirstCluster;
333 pEntry->FirstClusterHigh
334 =((VFATCCB *)(FileObject.FsContext2))->pFcb->entry.FirstClusterHigh;
335 memcpy(pEntry->Filename,".. ",11);
336 if(pEntry->FirstCluster==1 && DeviceExt->FatType!=FAT32)
337 pEntry->FirstCluster=0;
338 status=FsdWriteFile(DeviceExt,pFileObject,pEntry
339 ,sizeof(FATDirEntry),sizeof(FATDirEntry));
340 }
341 FsdCloseFile(DeviceExt,&FileObject);
342 ExFreePool(Buffer);
343 DPRINT("addentry ok\n");
344 return STATUS_SUCCESS;
345 }
346