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