3 * Revision 15.21 1999/09/11 17:05:14 Michiel
6 * Revision 15.20 1999/05/14 11:31:34 Michiel
7 * Long filename support implemented; bugfixes
9 * Revision 15.19 1999/05/10 23:53:29 Michiel
10 * hardlink bug (ST_LINKFILE/ST_LINKDIR) fixed
12 * Revision 15.18 1999/04/25 21:48:19 Michiel
13 * bug 00141 fixed: hardlink overwrite problem in NewFile()
15 * Revision 15.17 1999/04/23 11:12:39 Michiel
16 * optimisation: delfile is deleted when detected to be empty (during dirscan)
18 * Revision 15.16 1999/03/23 06:00:19 Michiel
19 * More informative error messages in setdeldir
20 * Maxdeldir bug in setdeldir fixed
22 * Revision 15.15 1999/03/09 10:34:02 Michiel
25 * Revision 15.14 1999/02/22 16:31:55 Michiel
26 * Changes for increasing deldir capacity
27 * Fixed link problems; new function MoveLink
29 * Revision 15.13 1998/09/27 11:26:37 Michiel
32 * Revision 15.12 1998/09/03 07:12:14 Michiel
34 * bugfixes 118, 121, 123 and superindexblocks and td64 support
36 * Revision 15.11 1997/03/03 22:04:04 Michiel
39 * Revision 15.10 1996/04/22 22:12:41 Michiel
40 * NewFile overwrite bug fix
41 * SetDate deldirfile bug fix
43 * Revision 15.9 1996/03/14 19:30:52 Michiel
44 * The connect anode for directory anode allocation now is the second anode,
45 * not the head anode --> better large directory performance
46 * NewFile does not call SearchInDir anymore --> better (large) dir perf.
49 * Revision 15.8 1996/03/07 10:09:09 Michiel
50 * rename bug fixed (wt)
52 * Revision 15.7 1996/01/30 12:47:46 Michiel
53 * --- working tree overlap ---
55 * Notify-update changes
57 * Revision 15.6 1995/12/29 11:02:43 Michiel
58 * SetRollover extended
60 * Revision 15.4 1995/12/21 12:00:51 Michiel
61 * bugfix: newfile didn't clear extrafields/filetype
62 * Now using FreeBlockAC directly instead of buggy FreeAnodeBlocksAC
64 * Revision 15.3 1995/12/20 11:54:19 Michiel
67 * Revision 15.2 1995/12/07 15:25:38 Michiel
68 * rollover support and bugfixes
70 * Revision 15.1 1995/11/15 15:41:17 Michiel
71 * Postponed operation support:
72 * AllocDeldirSlot, AddToDeldir, FreeAnodeBlocks, NewFile, DeleteObject, FreeAnodesInChain
73 * Rootblock extension: dates in Touch, Examine
75 * Revision 14.12 1995/11/07 14:54:13 Michiel
76 * Checks for ReservedAreaLock where needed
78 * Revision 14.11 1995/10/20 10:08:37 Michiel
79 * Anode reserved area adaptions (16.3)
81 * Revision 14.10 1995/10/04 08:58:17 Michiel
82 * FreeAnodeBlocks nu met anodechains geimplementeerd (FAB kan nu falen!).
84 * Revision 14.9 1995/10/03 10:59:37 Michiel
87 * Revision 14.8 1995/09/28 12:18:25 Michiel
88 * soft/hardlink namelength check added
89 * Deldir now frees oldblocknr of dirty member blocks
91 * Revision 14.7 1995/08/24 13:01:27 Michiel
92 * Touch now doesn't touch rootblock because that gives
93 * disk recognition problems when changing disks
95 * Revision 14.6 1995/08/21 04:18:49 Michiel
96 * RenameAndMove didn't check if source was deldir
98 * Revision 14.5 1995/08/16 14:31:34 Michiel
100 * added forced_RemoveDirEntry
102 * Revision 14.4 1995/08/04 04:17:09 Michiel
103 * SetProtection on deldir now allowed (using masks).
104 * SetOwner on deldir now allowed
105 * Touching deldir when file added to deldir
106 * Now using protection field of deldir for all deldirentries
108 * Revision 14.3 1995/08/02 16:09:39 Michiel
109 * Filename size limitation (31 characters)
110 * Empty filenames not accepted
112 * Revision 14.2 1995/07/28 07:58:01 Michiel
113 * Deldirentry valid check added
115 * Revision 14.1 1995/07/21 06:43:33 Michiel
117 * fixed ExNext problem (?)
118 * NewDir now does a diskwp. check
119 * Touch() now updates rootdir too
121 * Revision 13.11 1995/07/11 17:29:31 Michiel
122 * ErrorMsg () calls use messages.c variables now.
124 * Revision 13.10 1995/07/11 09:23:36 Michiel
127 * Revision 13.9 1995/07/07 14:41:21 Michiel
128 * no fib->fib_Reserved stuff
131 * Revision 13.8 1995/06/23 17:26:57 Michiel
132 * MakeDirEntry now also sets protection to default and owner to current (multiuser)
134 * Revision 13.7 1995/06/21 08:13:18 Michiel
135 * CheckVolume() calls removed (moved to dostohandlerinterface.c)
137 * Revision 13.6 1995/06/20 18:55:00 Michiel
138 * fixed a bug in FreeAnodeBlocks
139 * Examine checks softprotect
141 * Revision 13.5 1995/06/15 18:55:28 Michiel
144 * Revision 13.4 1995/06/08 11:12:32 Michiel
145 * Now GetFullPath checks if path is directory.
147 * Revision 13.3 1995/06/04 07:43:54 Michiel
148 * Longword protection implemented
150 * Revision 13.2 1995/05/03 19:14:13 Michiel
151 * LOCK added to create soft & hardlink
153 * Revision 13.1 1995/04/23 09:06:53 Michiel
154 * Rewritten direntry change routines,
155 * solving directory-order problem
157 * Revision 12.9 1995/04/18 17:08:16 Michiel
158 * CopyMem() to memcpy() and some cosmetic changes
160 * Revision 12.8 1995/04/14 10:03:53 Michiel
161 * 'Out of buffers' problem fixed.
163 * Revision 12.7 1995/04/05 12:24:43 Michiel
164 * Bugfix in ExamineAll
165 * Don't allow hardlinks when no dirextension
167 * Revision 12.6 1995/03/30 11:53:46 Michiel
168 * Rename now does a notify to sourcedir if rename across dirs
170 * Revision 12.5 1995/03/30 10:50:37 Michiel
171 * some notify stuff added
173 * Revision 12.4 1995/03/24 16:29:57 Michiel
174 * Softlink support added
175 * Hardlink bugs fixed
177 * Revision 12.3 1995/02/28 18:20:49 Michiel
178 * Link handling functions added: DeleteLink(), RemapLinks(), UpdateLinks(),
179 * FetchObject(), UpdateLinkDir().
180 * NewFile() takes over old direntry now, instead of delete/create.
181 * GetDir() resolves links.
183 * Revision 12.2 1995/02/24 07:12:41 Michiel
184 * CreateLink added, MakeDirEntry changed
186 * Revision 12.1 1995/02/23 06:57:01 Michiel
187 * Directory extension implemented
189 * Revision 11.5 1995/02/15 16:43:39 Michiel
191 * Using new headers (struct.h & blocks.h)
193 * Revision 11.4 1995/01/29 07:34:57 Michiel
194 * Bug in FreeAnodeBlocks fixed
196 * Revision 11.3 1995/01/24 09:49:51 Michiel
197 * Cache hashing added
199 * Revision 11.2 1995/01/18 04:29:34 Michiel
200 * Bugfixes. Now ready for beta release.
202 * Revision 11.1 1995/01/08 16:16:29 Michiel
205 * Revision 10.4 1994/11/15 17:52:30 Michiel
208 * Revision 10.3 1994/10/28 06:06:40 Michiel
209 * uses new listentry field anodenr
211 * Revision 10.2 1994/10/27 11:29:33 Michiel
212 * *** empty log message ***
214 * Revision 10.1 1994/10/24 11:16:28 Michiel
218 // anodenr in cdirblock !!! @->bugnr @@->currently wrong
220 #define __USE_SYSBASE
222 #include <exec/types.h>
223 #include <exec/memory.h>
224 #include <exec/devices.h>
226 #include <dos/exall.h>
227 #include <dos/filehandler.h>
228 #include <proto/intuition.h>
229 #include <proto/utility.h>
231 #include <proto/multiuser.h>
233 #include <intuition/intuition.h>
234 #include <intuition/intuitionbase.h>
246 #include "directory_protos.h"
247 #include "allocation_protos.h"
248 #include "volume_protos.h"
249 #include "lock_protos.h"
250 #include "disk_protos.h"
251 #include "anodes_protos.h"
252 #include "update_protos.h"
253 #include "lru_protos.h"
254 #include "ass_protos.h"
257 void PFSDoNotify(struct fileinfo
*object
, BOOL checkparent
, globaldata
* g
);
258 void PFSUpdateNotify(ULONG dirnode
, DSTR filename
, ULONG anodenr
, globaldata
* g
);
260 /**********************************************************************/
262 /**********************************************************************/
266 static UBYTE debugbuf
[120];
267 #define DebugOn debug++
268 #define DebugOff debug=0
269 #define DebugMsg(msg) if(debug) {NormalErrorMsg(msg, NULL);debug=0;}
270 #define DebugMsgNum(msg, num) sprintf(debugbuf, "%s 0x%08lx.", msg, num); \
271 if(debug) {NormalErrorMsg(debugbuf, NULL);debug=0;}
272 #define DebugMsgName(msg, name) sprintf(debugbuf, "%s >%s<.", msg, name); \
273 if(debug) {NormalErrorMsg(debugbuf, NULL);debug=0;}
278 #define DebugMsgNum(msg,num)
279 #define DebugMsgName(msg, name)
285 static BOOL
GetParentOf(union objectinfo
*path
, SIPTR
*error
, globaldata
*);
286 static BOOL
GetDir(STRPTR dirname
, union objectinfo
*path
, SIPTR
*error
, globaldata
*);
287 static BOOL
GetObject(STRPTR objectname
, union objectinfo
*path
, SIPTR
*error
, globaldata
*);
288 static BOOL
SearchInDir(ULONG dirnodenr
, STRPTR objectname
, union objectinfo
*info
, globaldata
* g
);
289 static void FillFib(struct direntry
*direntry
, struct FileInfoBlock
*fib
, globaldata
* g
);
291 static struct deldirentry
*SearchInDeldir(STRPTR delname
, union objectinfo
*result
, globaldata
*g
);
292 static BOOL
IsDelfileValid(struct deldirentry
*dde
, struct cdeldirblock
*ddblk
, globaldata
*g
);
293 static BOOL
BlockTaken(struct canode
*anode
, globaldata
*g
);
294 static void FillDelfileFib(struct deldirentry
*dde
, ULONG slotnr
, struct FileInfoBlock
*fib
, globaldata
*g
);
295 static struct deldirentry
*GetDeldirEntry(IPTR
*nr
, globaldata
*g
);
296 static ULONG
FillInDDEData(struct ExAllDataEXT
*buffer
, LONG type
, struct deldirentry
*dde
, ULONG ddenr
, ULONG spaceleft
, globaldata
*g
);
297 static struct cdeldirblock
*GetDeldirBlock(UWORD seqnr
, globaldata
*g
);
299 static void GetFirstEntry(lockentry_t
*, globaldata
*);
300 static ULONG
GetFirstNonEmptyDE(ULONG anodenr
, struct fileinfo
*, globaldata
*);
301 static void RemakeNextEntry(lockentry_t
*, struct FileInfoBlock
*, globaldata
*);
302 static ULONG
FillInData(struct ExAllDataEXT
*, LONG
, struct direntry
*, ULONG
, globaldata
*);
303 static BOOL
DeleteDir(union objectinfo
*, SIPTR
*, globaldata
*);
304 static BOOL
DirIsEmpty(ULONG
, globaldata
*);
305 static BOOL
MakeDirEntry(BYTE type
, UBYTE
*name
, UBYTE
*entrybuffer
, globaldata
* g
);
306 static BOOL
IsChildOf(union objectinfo child
, union objectinfo parent
, globaldata
* g
);
307 static BOOL
DeleteLink(struct fileinfo
*link
, SIPTR
*, globaldata
* g
);
308 static BOOL
RemapLinks(struct fileinfo
*object
, globaldata
* g
);
309 static void UpdateLinkDir(struct direntry
*object
, ULONG newdiran
, globaldata
* g
);
310 static void MoveLink(struct direntry
*object
, ULONG newdiran
, globaldata
*g
);
311 static void RenameAcrossDirs(struct fileinfo from
, struct direntry
*to
, union objectinfo
*destdir
, struct fileinfo
*result
, globaldata
* g
);
312 static void RenameWithinDir(struct fileinfo from
, struct direntry
*to
, struct fileinfo
*newinfo
, globaldata
* g
);
313 static void RenameInPlace(struct fileinfo from
, struct direntry
*to
, struct fileinfo
*result
, globaldata
* g
);
314 static struct direntry
*CheckFit(struct cdirblock
*blok
, int needed
, globaldata
* g
);
315 static BOOL
MoveToPrevious(struct fileinfo de
, struct direntry
*to
, struct fileinfo
*result
, globaldata
* g
);
316 static void RemoveDirEntry(struct fileinfo info
, globaldata
* g
);
317 static BOOL
AddDirectoryEntry(union objectinfo
*dir
, struct direntry
*newentry
, struct fileinfo
*newinfo
, globaldata
* g
);
318 static void UpdateChangedRef(struct fileinfo from
, struct fileinfo
*to
, int diff
, globaldata
* g
);
321 static int AllocDeldirSlot(globaldata
* g
);
322 static void AddToDeldir(union objectinfo
*info
, int ddnr
, globaldata
* g
);
324 static void AddToDeldir(union objectinfo
*info
, globaldata
* g
);
325 static BOOL
FreeAnodeBlocks(ULONG anodenr
, enum freeblocktype freenodes
, globaldata
* g
);
328 /**********************************************************************/
329 /* SEARCH IN DIRECTORY */
330 /* SEARCH IN DIRECTORY */
331 /* SEARCH IN DIRECTORY */
332 /**********************************************************************/
334 /* GetFullPath converts a relative path to an absolute path.
335 * The fileinfo of the new path is returned in [result].
336 * The return value is the filename without path.
340 * : after '/' or at the beginning ==> root
341 * : after [name] ==> volume [name]
342 * / after / or ':' or at the beginning ==> parent
343 * / after dir ==> get dir
344 * / after file ==> error (ALWAYS) (AMIGADOS ok if LAST file)
346 * IN basispath, filename, g
347 * OUT fullpath, error
349 * If only a partial path is found, a pointer to the unparsed part
350 * will be stored in g->unparsed.
352 UBYTE
*GetFullPath(union objectinfo
*basispath
, STRPTR filename
,
353 union objectinfo
*fullpath
, SIPTR
*error
, globaldata
* g
)
355 UBYTE
*pathpart
, parttype
;
357 BOOL eop
= FALSE
, success
= TRUE
;
358 struct volumedata
*volume
;
360 // VVV Init:getrootvolume
361 ENTER("GetFullPath");
366 *fullpath
= *basispath
;
368 GetRoot(fullpath
, g
);
370 /* The basispath should not be a file
371 * BTW: softlink is illegal too, but not possible
373 if (IsFile(*fullpath
) || IsDelFile(*fullpath
))
375 *error
= ERROR_OBJECT_WRONG_TYPE
;
379 /* check if device present */
380 if (IsVolume(*fullpath
) || IsDelDir(*fullpath
))
381 volume
= fullpath
->volume
.volume
;
383 volume
= fullpath
->file
.dirblock
->volume
;
385 if (!CheckVolume(volume
, 0, error
, g
))
388 /* extend base-path using filename and
389 * continue until path complete (eop = end of path)
394 index
= strcspn(filename
, "/:");
395 parttype
= filename
[index
];
396 filename
[index
] = 0x0;
405 if (*pathpart
== 0x0)
406 success
= GetParentOf(fullpath
, error
, g
);
408 success
= GetDir(pathpart
, fullpath
, error
, g
);
415 filename
[index
] = parttype
;
419 /* return pathrest for readlink() */
420 if (*error
== ERROR_IS_SOFT_LINK
)
421 g
->unparsed
= filename
+ index
;
422 else if (*error
== ERROR_OBJECT_NOT_FOUND
)
423 g
->unparsed
= filename
;
428 filename
+= index
+ 1;
434 BOOL
GetRoot(union objectinfo
* path
, globaldata
* g
)
436 UpdateCurrentDisk(g
);
437 path
->volume
.root
= 0;
438 path
->volume
.volume
= g
->currentvolume
;
442 /* pre: - path <> 0 and volume or directory
443 * result back in path
445 static BOOL
GetParentOf(union objectinfo
*path
, SIPTR
*error
, globaldata
* g
)
448 union objectinfo info
;
451 ok
= GetParent(&info
, path
, error
, g
);
455 /* pre: - path <> 0 and volume of directory
456 * - dirname without path; strlen(dirname) > 0
457 * result back in path
459 static BOOL
GetDir(STRPTR dirname
, union objectinfo
*path
, SIPTR
*error
, globaldata
* g
)
463 found
= GetObject(dirname
, path
, error
, g
);
466 if (g
->deldirenabled
&& IsDelDir(*path
))
470 /* check if found directory */
472 if (!found
|| IsFile(*path
) || IsDelFile(*path
))
474 if (!found
|| IsFile(*path
))
477 *error
= ERROR_OBJECT_NOT_FOUND
; // DOPUS doesn't like DIR_NOT_FOUND
481 /* check if softlink */
482 if (IsSoftLink(*path
))
484 *error
= ERROR_IS_SOFT_LINK
;
489 if (path
->file
.direntry
->type
== ST_LINKDIR
)
491 struct extrafields extrafields
;
492 struct canode linknode
;
494 GetExtraFields(path
->file
.direntry
, &extrafields
);
495 GetAnode(&linknode
, path
->file
.direntry
->anode
, g
);
496 if (!FetchObject(linknode
.clustersize
, extrafields
.link
, path
, g
))
503 /* pre: - path<>0 and volume of directory
504 * - objectname without path; strlen(objectname) > 0
505 * result back in path
507 static BOOL
GetObject(STRPTR objectname
, union objectinfo
*path
, SIPTR
*error
, globaldata
*g
)
514 found
= (SearchInDeldir(objectname
, path
, g
) != NULL
);
520 anodenr
= ANODE_ROOTDIR
;
522 anodenr
= path
->file
.direntry
->anode
;
524 DB(Trace(1, "GetObject", "parent anodenr %lx\n", anodenr
));
525 found
= SearchInDir(anodenr
, objectname
, path
, g
);
531 if (g
->deldirenabled
&& IsVolume(*path
))
533 if (stricmp(deldirname
+1, objectname
) == 0)
535 path
->deldir
.special
= SPECIAL_DELDIR
;
536 path
->deldir
.volume
= g
->currentvolume
;
541 *error
= ERROR_OBJECT_NOT_FOUND
;
550 * FindObject searches the object 'fname' in directory 'directory'.
551 * FindObject zoekt het object 'fname' in directory 'directory'.
552 * Interpret empty filename as parent and ":" as root.
553 * Does not use multiple-assign-list
555 * input : - [directory]: the 'root' directory of the search
556 * - [objectname]: file to be found, including path
558 * output: - [object]: If file found : fileinfo of object
559 * If path found : fileinfo of directory
560 * - [error]: Errornumber as result = DOSFALSE; otherwise 0
562 * result: DOSTRUE (-1) = file found (->in fileinfo)
563 * DOSFALSE (0) = error
565 * If only a partial path is found, a pointer to the unparsed part
566 * will be stored in g->unparsed.
568 BOOL
FindObject(union objectinfo
*directory
, STRPTR objectname
,
569 union objectinfo
*object
, SIPTR
*error
, globaldata
*g
)
575 filename
= GetFullPath(directory
, objectname
, object
, error
, g
);
579 DB(Trace(2, "FindObject", "!filename %s\n", objectname
));
583 /* path only (dir or volume) */
587 /* there is a filepart (file or dir) */
588 ok
= GetObject(filename
, object
, error
, g
);
589 if (!ok
&& (*error
== ERROR_OBJECT_NOT_FOUND
))
590 g
->unparsed
= filename
;
598 * childanodenr = anodenr of start directory (the child)
599 * parentanodenr = anodenr of directory containing childanodenr (the parent)
600 * childfi == parentfi can be dangerous
601 * in:childfi; out:parentfi, error
603 BOOL
GetParent(union objectinfo
*childfi
, union objectinfo
*parentfi
, SIPTR
*error
, globaldata
*g
)
606 struct cdirblock
*dirblock
;
608 ULONG anodeoffset
= 0;
609 ULONG childanodenr
, parentanodenr
;
610 BOOL eod
= FALSE
, eob
= FALSE
, found
= FALSE
;
612 // -I- Find anode of parent
613 if (!childfi
|| IsVolume(*childfi
)) // child is rootdir
615 *error
= 0x0; /* No error; just return NULL */
620 if (g
->deldirenabled
)
622 if (IsDelDir(*childfi
))
623 return GetRoot(parentfi
, g
);
625 if (IsDelFile(*childfi
))
627 parentfi
->deldir
.special
= SPECIAL_DELDIR
;
628 parentfi
->deldir
.volume
= g
->currentvolume
;
634 childanodenr
= childfi
->file
.dirblock
->blk
.anodenr
; /* the directory 'child' is in */
635 parentanodenr
= childfi
->file
.dirblock
->blk
.parent
; /* the directory 'childanodenr' is in */
637 // -II- check if in root
638 if (parentanodenr
== 0) /* child is in rootdir */
640 parentfi
->volume
.root
= 0;
641 parentfi
->volume
.volume
= childfi
->file
.dirblock
->volume
;
645 // -III- get parentdirectory and find direntry
646 GetAnode(&anode
, parentanodenr
, g
);
647 while (!found
&& !eod
)
649 dirblock
= LoadDirBlock(anode
.blocknr
+ anodeoffset
, g
);
652 de
= FIRSTENTRY(dirblock
);
655 while (!found
&& !eob
)
657 found
= (de
->anode
== childanodenr
);
658 eob
= (de
->next
== 0);
664 eod
= !NextBlock(&anode
, &anodeoffset
, g
);
674 DB(Trace(1, "GetParent", "DiskNotValidated %ld\n", childanodenr
));
675 *error
= ERROR_DISK_NOT_VALIDATED
;
679 parentfi
->file
.direntry
= de
;
680 parentfi
->file
.dirblock
= dirblock
;
688 * Search an object in a directory and return the fileinfo
690 * input : - dirnodenr: anodenr of directory to search in
691 * - objectname: found object (without path)
693 * output: - info: objectinfo of found object
697 static BOOL
SearchInDir(ULONG dirnodenr
, STRPTR objectname
, union objectinfo
*info
, globaldata
* g
)
700 struct cdirblock
*dirblock
;
701 struct direntry
*entry
= NULL
;
702 BOOL found
= FALSE
, eod
= FALSE
;
704 UBYTE intl_name
[PATHSIZE
];
706 ENTER("SearchInDir");
707 ctodstr(objectname
, intl_name
);
710 if (intl_name
[0] > FILENAMESIZE
- 1)
711 intl_name
[0] = FILENAMESIZE
- 1;
713 intltoupper(intl_name
); /* international uppercase objectname */
714 GetAnode(&anode
, dirnodenr
, g
);
716 dirblock
= LoadDirBlock(anode
.blocknr
, g
);
718 while (dirblock
&& !found
&& !eod
) /* eod stands for end-of-dir */
720 entry
= (struct direntry
*)(&dirblock
->blk
.entries
);
725 found
= intlcmp(intl_name
, DIRENTRYNAME(entry
));
728 entry
= NEXTENTRY(entry
);
731 /* load next block */
734 if (NextBlock(&anode
, &anodeoffset
, g
))
735 dirblock
= LoadDirBlock(anode
.blocknr
+ anodeoffset
, g
);
748 info
->file
.direntry
= entry
;
749 info
->file
.dirblock
= dirblock
;
759 * Search object by anodenr in directory
760 * in: diranodenr, target: anodenr of target and the anodenr of the directory to search in
761 * out: result: an objectinfo to the object, if found
764 BOOL
FetchObject(ULONG diranodenr
, ULONG target
, union objectinfo
* result
, globaldata
* g
)
767 struct cdirblock
*dirblock
;
769 ULONG anodeoffset
= 0;
770 BOOL eod
= FALSE
, found
= FALSE
;
772 /* Get directory and find object */
773 GetAnode(&anode
, diranodenr
, g
);
774 while (!found
&& !eod
)
776 dirblock
= LoadDirBlock(anode
.blocknr
+ anodeoffset
, g
);
779 de
= FIRSTENTRY(dirblock
);
782 if (!(found
= (de
->anode
== target
)))
789 eod
= !NextBlock(&anode
, &anodeoffset
, g
);
798 result
->file
.dirblock
= dirblock
;
799 result
->file
.direntry
= de
;
804 /**********************************************************************/
805 /* GET DIRECTORY CONTENTS */
806 /* GET DIRECTORY CONTENTS */
807 /* GET DIRECTORY CONTENTS */
808 /**********************************************************************/
815 * - fill in fileinfoblock
816 * - prepares for ExamineNextFile
818 * *error: error if failure; else undefined
820 * - fib_DirEntryType must be equal to fib_EntryType
822 BOOL
ExamineFile(listentry_t
*file
, struct FileInfoBlock
* fib
, SIPTR
*error
, globaldata
* g
)
824 struct volumedata
*volume
;
826 struct crootblockextension
*rext
;
827 union objectinfo
*info
;
830 /* volume must be or become currentvolume */
832 volume
= g
->currentvolume
;
834 volume
= file
->volume
;
837 fib
->fib_DiskKey
= (IPTR
)file
; // I use it as dir-block-number for ExNext
838 if (!file
|| IsVolumeEntry(file
))
840 fib
->fib_DirEntryType
= \
841 fib
->fib_EntryType
= ST_USERDIR
;
842 fib
->fib_Protection
= (g
->diskstate
== ID_WRITE_PROTECTED
) || g
->softprotect
;
844 fib
->fib_NumBlocks
= 0;
846 if (volume
->rblkextension
)
848 fib
->fib_Date
.ds_Days
= (ULONG
)volume
->rblkextension
->blk
.root_date
[0];
849 fib
->fib_Date
.ds_Minute
= (ULONG
)volume
->rblkextension
->blk
.root_date
[1];
850 fib
->fib_Date
.ds_Tick
= (ULONG
)volume
->rblkextension
->blk
.root_date
[2];
854 fib
->fib_Date
.ds_Days
= (ULONG
)volume
->rootblk
->creationday
;
855 fib
->fib_Date
.ds_Minute
= (ULONG
)volume
->rootblk
->creationminute
;
856 fib
->fib_Date
.ds_Tick
= (ULONG
)volume
->rootblk
->creationtick
;
859 CopyMem(volume
->rootblk
->diskname
, fib
->fib_FileName
, volume
->rootblk
->diskname
[0] + 1);
860 fib
->fib_Comment
[0] = 0x0;
861 //fib->fib_Reserved[0] = 0x0;
869 rext
= volume
->rblkextension
;
870 fib
->fib_DiskKey
= 0;
871 fib
->fib_DirEntryType
= \
872 fib
->fib_EntryType
= ST_USERDIR
;
873 fib
->fib_Protection
= (ULONG
)rext
->blk
.dd_protection
;
875 fib
->fib_NumBlocks
= 0;
876 fib
->fib_Date
.ds_Days
= (ULONG
)rext
->blk
.dd_creationday
;
877 fib
->fib_Date
.ds_Minute
= (ULONG
)rext
->blk
.dd_creationminute
;
878 fib
->fib_Date
.ds_Tick
= (ULONG
)rext
->blk
.dd_creationtick
;
879 strcpy(fib
->fib_FileName
, deldirname
);
880 fib
->fib_Comment
[0] = 0x0;
881 fib
->fib_OwnerUID
= (ULONG
)rext
->blk
.dd_uid
;
882 fib
->fib_OwnerGID
= (ULONG
)rext
->blk
.dd_gid
;
884 /* prepare ExNext() */
885 ((lockentry_t
*)file
)->nextanode
= 0;
888 else if (IsDelFile(*info
))
890 FillDelfileFib(NULL
, info
->delfile
.slotnr
, fib
, g
);
896 FillFib(file
->info
.file
.direntry
, fib
, g
);
902 /* prepare examinenext */
903 if (!file
|| file
->type
.flags
.dir
)
904 GetFirstEntry((lockentry_t
*)file
, g
);
913 * - used to obtain info on all directory entries
914 * - fill in fileinfoblock
918 * - fib_DirEntryType must be equal to fib_EntryType
919 * - it is allowed to stop invoking before end of dir
920 * - for old compatibility: only DiskKey and FileName guaranteed to be the same
921 * on subsequent calls
922 * - it is possible to receive other packets between ExNext's -> special cases
923 * - the lock is passed is not always the same, but it is a lock to the same object
927 * - fib_DiskKey contains address of lock; different->problems
929 * lock->nextentry contains pointer to be fetched entry. End of dir <=>
930 * lock->nextentry == {NULL, NULL}
933 BOOL
ExamineNextFile(lockentry_t
*file
, struct FileInfoBlock
* fib
,
934 SIPTR
*error
, globaldata
* g
)
937 struct direntry
*direntry
;
941 /* file must be lock on dir; NULL lock not allowed */
942 if (!file
|| !file
->le
.type
.flags
.dir
)
944 *error
= ERROR_OBJECT_WRONG_TYPE
;
949 if (IsDelDir(file
->le
.info
))
951 struct deldirentry
*dde
;
953 dde
= GetDeldirEntry(&fib
->fib_DiskKey
, g
);
956 FillDelfileFib(dde
, fib
->fib_DiskKey
, fib
, g
);
962 *error
= ERROR_NO_MORE_ENTRIES
;
968 /* check if same lock used */
969 if ((IPTR
)file
!= (IPTR
)fib
->fib_DiskKey
)
971 DB(Trace(1, "ExamineNextFile", "Other lock!!\n"));
972 RemakeNextEntry(file
, fib
, g
);
975 /* Check if end of dir */
976 if (file
->nextentry
.dirblock
== NULL
)
978 *error
= ERROR_NO_MORE_ENTRIES
;
983 direntry
= file
->nextentry
.direntry
;
986 fib
->fib_DiskKey
= (IPTR
)file
; // I use it as dir-block-number
987 FillFib(direntry
, fib
, g
);
991 *error
= ERROR_NO_MORE_ENTRIES
;
992 ErrorMsg(AFS_ERROR_EX_NEXT_FAIL
, NULL
, g
);
997 GetNextEntry(file
, g
);
1002 /* Fill fileinfoblock of a file
1004 static void FillFib(struct direntry
*direntry
, struct FileInfoBlock
*fib
, globaldata
* g
)
1006 struct extrafields extrafields
;
1010 size
= GetDEFileSize(direntry
, g
);
1011 /* fib->fib_DiskKey done by Examine(Next) */
1012 fib
->fib_DirEntryType
= direntry
->type
;
1013 fib
->fib_EntryType
= direntry
->type
;
1014 fib
->fib_Protection
= (ULONG
)direntry
->protection
;
1015 fib
->fib_Size
= GetDEFileSize32(direntry
, g
);
1016 fib
->fib_NumBlocks
= (size
/ BLOCKSIZE
) + (size
% BLOCKSIZE
> 0);
1017 fib
->fib_Date
.ds_Days
= direntry
->creationday
;
1018 fib
->fib_Date
.ds_Minute
= direntry
->creationminute
;
1019 fib
->fib_Date
.ds_Tick
= direntry
->creationtick
;
1020 strncpy(fib
->fib_FileName
, (UBYTE
*)&direntry
->nlength
, direntry
->nlength
+ 1);
1021 fib
->fib_FileName
[direntry
->nlength
+ 1] = 0;
1023 comment
= (UBYTE
*)&direntry
->startofname
+ direntry
->nlength
;
1024 strncpy(fib
->fib_Comment
, comment
, min(*comment
+ 1, CMSIZE
));
1025 fib
->fib_Comment
[*comment
+ 1] = 0;
1027 if (g
->dirextension
)
1029 GetExtraFields(direntry
, &extrafields
);
1030 fib
->fib_Protection
|= extrafields
.prot
;
1031 fib
->fib_OwnerUID
= extrafields
.uid
;
1032 fib
->fib_OwnerGID
= extrafields
.gid
;
1035 if (direntry
->type
== ST_ROLLOVERFILE
)
1036 fib
->fib_Size
= extrafields
.virtualsize
;
1041 /* Fill 'nextentry' of listentry [le]. If directory contains no entries,
1042 * nextentry will be set to NULL
1043 * > not for deldirs <
1045 static void GetFirstEntry(lockentry_t
*le
, globaldata
* g
)
1050 anodenr
= ANODE_ROOTDIR
;
1052 anodenr
= le
->le
.anodenr
;
1054 le
->nextanode
= GetFirstNonEmptyDE(anodenr
, &le
->nextentry
, g
);
1057 /* Get first non empty direntry starting from anode [anodenr]
1058 * Returns {NULL, NULL} if end of dir
1060 static ULONG
GetFirstNonEmptyDE(ULONG anodenr
, struct fileinfo
*info
, globaldata
*g
)
1062 struct canode anode
;
1066 anode
.next
= anodenr
;
1069 nextsave
= anode
.next
;
1072 GetAnode(&anode
, anode
.next
, g
);
1073 info
->dirblock
= LoadDirBlock(anode
.blocknr
, g
);
1075 info
->direntry
= FIRSTENTRY(info
->dirblock
);
1078 if (!nextsave
|| !info
->dirblock
)
1080 info
->direntry
= NULL
;
1081 info
->dirblock
= NULL
;
1084 else if (info
->direntry
->next
!= 0)
1086 LOCK(info
->dirblock
);
1095 static void RemakeNextEntry(lockentry_t
*file
, struct FileInfoBlock
*fib
, globaldata
*g
)
1098 UBYTE filename
[FNSIZE
];
1100 anodenr
= file
->le
.anodenr
;
1101 if (ddstricmp(fib
->fib_FileName
, file
->le
.volume
->rootblk
->diskname
))
1102 GetFirstEntry(file
, g
);
1105 BCPLtoCString(filename
, fib
->fib_FileName
);
1106 if (!SearchInDir(anodenr
, filename
, (union objectinfo
*)&file
->nextentry
, g
))
1108 file
->nextentry
.dirblock
= NULL
;
1109 file
->nextentry
.direntry
= NULL
;
1110 file
->nextanode
= anodenr
;
1113 GetNextEntry(file
, g
);
1117 void GetNextEntry(lockentry_t
*file
, globaldata
* g
)
1119 struct canode anode
;
1122 file
->nextentry
.direntry
= NEXTENTRY(file
->nextentry
.direntry
);
1124 /* no next entry? -> next block */
1125 if (!file
->nextentry
.direntry
->next
)
1127 /* NB: 'nextanode' is een verwarrende naam */
1128 GetAnode(&anode
, file
->nextanode
, g
);
1129 file
->nextanode
= GetFirstNonEmptyDE(anode
.next
, &file
->nextentry
, g
);
1135 * fill buffer with directory information
1137 * Note: +- 2000 stack needed
1139 static ULONG
FillInData(struct ExAllDataEXT
*buffer
, LONG type
,
1140 struct direntry
*direntry
, ULONG spaceleft
, globaldata
*g
)
1142 UWORD nameoffset
, commentoffset
= 0;
1143 UBYTE
*name
, *comment
= NULL
;
1145 struct extrafields extrafields
;
1147 /* get location to put name */
1151 size
= offsetof(struct ExAllDataEXT
, ed_Type
);
1155 size
= offsetof(struct ExAllDataEXT
, ed_Size
);
1159 size
= offsetof(struct ExAllDataEXT
, ed_Prot
);
1163 size
= offsetof(struct ExAllDataEXT
, ed_Days
);
1167 size
= offsetof(struct ExAllDataEXT
, ed_Comment
);
1171 size
= offsetof(struct ExAllDataEXT
, ed_OwnerUID
);
1175 #if EXTENDED_PACKETS_MORPHOS
1176 size
= offsetof(struct ExAllDataEXT
, ed_Size64
);
1181 size
= sizeof(struct ExAllDataEXT
);
1185 size
= offsetof(struct ExAllDataEXT
, ed_Type
);
1191 name
= &direntry
->nlength
;
1194 /* size of comment */
1195 if (type
>= ED_COMMENT
)
1197 commentoffset
= size
;
1198 comment
= COMMENT(direntry
);
1199 size
+= *comment
+ 1;
1203 size
= (size
+ 1) & 0xfffe;
1204 if (size
> spaceleft
)
1207 /* get extra fields */
1208 GetExtraFields(direntry
, &extrafields
);
1211 buffer
->ed_Next
= NULL
;
1214 #if EXTENDED_PACKETS_MORPHOS
1217 if (direntry
->type
== ST_ROLLOVERFILE
)
1218 buffer
->ed_Size64
= extrafields
.virtualsize
;
1221 buffer
->ed_Size64
= GetDEFileSize(direntry
, g
);
1224 buffer
->ed_OwnerUID
= extrafields
.uid
;
1225 buffer
->ed_OwnerGID
= extrafields
.gid
;
1228 buffer
->ed_Comment
= (UBYTE
*)buffer
+ commentoffset
;
1229 strncpy((UBYTE
*)buffer
+ commentoffset
, comment
+ 1, *comment
);
1230 *((UBYTE
*)buffer
+ commentoffset
+ *comment
) = 0x0;
1233 buffer
->ed_Days
= direntry
->creationday
;
1234 buffer
->ed_Mins
= direntry
->creationminute
;
1235 buffer
->ed_Ticks
= direntry
->creationtick
;
1238 buffer
->ed_Prot
= (ULONG
)direntry
->protection
| extrafields
.prot
;
1242 if (direntry
->type
== ST_ROLLOVERFILE
)
1243 buffer
->ed_Size
= extrafields
.virtualsize
;
1246 buffer
->ed_Size
= GetDEFileSize32(direntry
, g
);
1249 buffer
->ed_Type
= direntry
->type
;
1253 strncpy((UBYTE
*)buffer
+ nameoffset
,
1254 (UBYTE
*)&direntry
->startofname
, *name
);
1255 *((UBYTE
*)buffer
+ nameoffset
+ *name
) = 0x0;
1258 buffer
->ed_Name
= (UBYTE
*)buffer
+ nameoffset
;
1264 BOOL
ExamineAll(lockentry_t
*object
, UBYTE
*buffer
, ULONG buflen
,
1265 LONG type
, struct ExAllControl
* ctrl
, SIPTR
*error
, globaldata
* g
)
1267 struct direntry
*direntry
;
1268 struct ExAllDataEXT
*lasteaentry
= NULL
;
1269 ULONG spaceleft
, size
;
1273 struct deldirentry
*dde
;
1276 ENTER("ExamineAll");
1278 /* init and check */
1279 if (!object
|| !object
->le
.type
.flags
.dir
)
1281 *error
= ERROR_OBJECT_WRONG_TYPE
;
1285 /* check type field */
1286 #if EXTENDED_PACKETS_MORPHOS
1287 if (type
> ED_SIZE64
|| type
< ED_NAME
)
1289 if (type
> ED_OWNER
|| type
< ED_NAME
)
1292 *error
= ERROR_BAD_NUMBER
;
1298 j
= 0; // # direntries in buffer
1301 if (IsDelDir(object
->le
.info
))
1304 while ((dde
= GetDeldirEntry(&ctrl
->eac_LastKey
, g
)))
1308 size
= FillInDDEData((struct ExAllDataEXT
*)buffer
, type
, dde
, ctrl
->eac_LastKey
,
1312 /* check if entry is wanted (needs 1500 stack) */
1313 if (ctrl
->eac_MatchFunc
)
1314 wanted
= CallHookPkt(ctrl
->eac_MatchFunc
, &type
, buffer
);
1315 else if (ctrl
->eac_MatchString
)
1316 wanted
= MatchPatternNoCase(ctrl
->eac_MatchString
,
1317 ((struct ExAllDataEXT
*)buffer
)->ed_Name
);
1321 /* if so update statistics */
1325 lasteaentry
->ed_Next
= (struct ExAllDataEXT
*)buffer
;
1327 lasteaentry
= (struct ExAllDataEXT
*)buffer
;
1333 ctrl
->eac_LastKey
++;
1336 break; // doesn't fit
1341 ctrl
->eac_Entries
= j
;
1344 *error
= ERROR_NO_MORE_ENTRIES
;
1352 /* check if it's the first call and if same lock is used */
1353 if (ctrl
->eac_LastKey
== 0)
1354 GetFirstEntry(object
, g
);
1355 else if ((IPTR
)object
!= (IPTR
)ctrl
->eac_LastKey
)
1357 *error
= ERROR_NO_MORE_ENTRIES
;
1361 DB(Trace(1, "ExamineAll", "matchfunc = %lx matchstring = %s\n", ctrl
->eac_MatchFunc
, ctrl
->eac_MatchString
));
1368 if (!(eod
= (object
->nextentry
.dirblock
== NULL
)))
1369 direntry
= object
->nextentry
.direntry
;
1373 size
= FillInData((struct ExAllDataEXT
*)buffer
, type
, direntry
,
1378 /* check if entry is wanted (needs 1500 stack) */
1379 if (ctrl
->eac_MatchFunc
)
1380 wanted
= CallHookPkt(ctrl
->eac_MatchFunc
, &type
, buffer
);
1381 else if (ctrl
->eac_MatchString
)
1382 wanted
= MatchPatternNoCase(ctrl
->eac_MatchString
,
1383 ((struct ExAllDataEXT
*)buffer
)->ed_Name
);
1387 /* if so update statistics */
1391 lasteaentry
->ed_Next
= (struct ExAllDataEXT
*)buffer
;
1393 lasteaentry
= (struct ExAllDataEXT
*)buffer
;
1399 GetNextEntry(object
, g
);
1402 break; // doesn't fit
1407 ctrl
->eac_LastKey
= (IPTR
)object
;
1408 ctrl
->eac_Entries
= j
;
1412 *error
= ERROR_NO_MORE_ENTRIES
;
1419 /**********************************************************************/
1420 /* ADD AND REMOVE FILES */
1421 /* ADD AND REMOVE FILES */
1422 /* ADD AND REMOVE FILES */
1423 /**********************************************************************/
1427 * NewFile creates a new file in a [directory] on currentvolume
1429 * input : - [directory]: directory of file;
1430 * - [filename]: name (without path) of file
1431 * - found: flag, file already present?. If so newfile == old
1433 * output: - [newfile]: fileinfo of new file (struct is managed by caller)
1434 * - [directory]: fileinfo of parent (can have changed if hardlink)
1436 * result: errornr; 0 = success
1438 * maxneeds: 1 nd + 2 na = 3 res
1440 * Note: 'directory' and 'newfile' may point to the same.
1442 ULONG
NewFile (BOOL found
, union objectinfo
*directory
, STRPTR filename
, union objectinfo
*newfile
, globaldata
*g
)
1444 union objectinfo info
;
1447 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
1448 struct extrafields extrafields
;
1449 struct direntry
*destentry
;
1450 struct canode anode
;
1453 struct anodechain
*achain
;
1456 DB(Trace(10, "NewFile", "%s\n", filename
));
1457 /* check disk-writeprotection etc */
1458 if (!CheckVolume(g
->currentvolume
, 1, &error
, g
))
1462 if (IsDelDir(*directory
))
1463 return ERROR_WRITE_PROTECTED
;
1466 /* check reserved area lock */
1467 if (ReservedAreaIsLocked
)
1468 return ERROR_DISK_FULL
;
1470 /* truncate filename to 31 characters */
1471 if (!(l
= strlen(filename
)))
1472 return ERROR_INVALID_COMPONENT_NAME
;
1473 if (l
> FILENAMESIZE
- 1)
1474 filename
[FILENAMESIZE
- 1] = 0x0;
1479 * new version: take over direntry
1480 * (used to simply delete old and make new)
1482 info
.file
= newfile
->file
;
1483 anodenr
= FIANODENR(&info
.file
);
1485 /* Check deleteprotection */
1486 if (IsVolume(info
) || info
.file
.direntry
->protection
& FIBF_DELETE
)
1487 return ERROR_DELETE_PROTECTED
;
1489 /* If link, get real object. After this it has become a
1492 if ((info
.file
.direntry
->type
== ST_LINKFILE
) ||
1493 (info
.file
.direntry
->type
== ST_LINKDIR
))
1495 struct canode linknode
;
1497 GetExtraFields(info
.file
.direntry
, &extrafields
);
1498 anodenr
= extrafields
.link
;
1499 GetAnode(&linknode
, info
.file
.direntry
->anode
, g
);
1500 if (!FetchObject(linknode
.clustersize
, anodenr
, &info
, g
))
1501 return ERROR_OBJECT_NOT_FOUND
;
1503 /* have to check protection again */
1504 if (info
.file
.direntry
->protection
& FIBF_DELETE
)
1505 return ERROR_DELETE_PROTECTED
;
1508 if (!GetParent(&info
, directory
, &error
, g
))
1509 return ERROR_OBJECT_NOT_FOUND
;
1512 /* Check if there are outstanding locks on object */
1513 if (ScanLockList(HeadOf(&g
->currentvolume
->fileentries
), anodenr
))
1515 DB(Trace(1, "NewFile", "object in use"));
1516 return ERROR_OBJECT_IN_USE
;
1519 if (!(achain
= GetAnodeChain(anodenr
, g
)))
1520 return ERROR_NO_FREE_STORE
;
1522 /* Free used space */
1523 if (g
->deldirenabled
&& info
.file
.direntry
->type
== ST_FILE
)
1527 /* free a slot to put old version in, inter. update possible */
1528 ddslot
= AllocDeldirSlot(g
);
1530 /* make replacement anode, because we want to reuse the old one */
1531 info
.file
.direntry
->anode
= achain
->head
.an
.nr
= AllocAnode(0, g
);
1532 SaveAnode(&achain
->head
.an
, achain
->head
.an
.nr
, g
);
1533 AddToDeldir(&info
, ddslot
, g
);
1534 info
.file
.direntry
->anode
= anodenr
;
1537 /* Rollover files are essentially just 'reset' by overwriting:
1538 * only the virtualsize and offset are set to zero (extrafields)
1539 * Other files are deleted and recreated as a new file.
1541 if (info
.file
.direntry
->type
!= ST_ROLLOVERFILE
)
1543 /* Change directory entry */
1544 SetDEFileSize(info
.file
.direntry
, 0, g
);
1545 info
.file
.direntry
->type
= ST_FILE
;
1546 MakeBlockDirty((struct cachedblock
*)info
.file
.dirblock
, g
);
1549 anode
.clustersize
= 0;
1550 anode
.blocknr
= 0xffffffff;
1552 SaveAnode(&anode
, anodenr
, g
);
1554 /* Delete old file (update possible) */
1555 if (g
->deldirenabled
&& info
.file
.direntry
->type
== ST_FILE
)
1556 FreeBlocksAC(achain
, UINT_MAX
, keepanodes
, g
);
1558 FreeBlocksAC(achain
, UINT_MAX
, freeanodes
, g
);
1559 DetachAnodeChain(achain
, g
);
1562 /* Clear direntry extrafields */
1563 destentry
= (struct direntry
*)entrybuffer
;
1564 memcpy(destentry
, info
.file
.direntry
, info
.file
.direntry
->next
);
1565 GetExtraFields(info
.file
.direntry
, &extrafields
);
1566 extrafields
.virtualsize
= extrafields
.rollpointer
= 0;
1567 AddExtraFields(destentry
, &extrafields
);
1568 ChangeDirEntry(info
.file
, destentry
, directory
, &info
.file
, g
);
1569 newfile
->file
= info
.file
;
1573 /* direntry alloceren en invullen */
1574 if (MakeDirEntry(ST_FILE
, filename
, entrybuffer
, g
))
1576 if (AddDirectoryEntry(directory
, (struct direntry
*)entrybuffer
, &newfile
->file
, g
))
1579 FreeAnode(((struct direntry
*)entrybuffer
)->anode
, g
);
1582 return ERROR_DISK_FULL
;
1591 * - returns fileentry (!) with exclusive lock
1595 * - check if file/dir exists
1597 * - make first dirblock
1599 * Similar to NewFile()
1601 * maxneeds: 2 nd, 3 na = 2 nablk : 4 res
1603 lockentry_t
*NewDir(union objectinfo
*parent
, STRPTR dirname
, SIPTR
*error
, globaldata
* g
)
1605 union objectinfo info
;
1606 listentry_t
*fileentry
;
1608 struct cdirblock
*blk
;
1609 ULONG parentnr
, blocknr
;
1610 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
1613 DB(Trace(1, "NewDir", "%s\n", dirname
));
1615 /* check disk-writeprotection etc */
1616 if (!CheckVolume(g
->currentvolume
, 1, error
, g
))
1620 if (IsDelDir(*parent
))
1622 *error
= ERROR_WRITE_PROTECTED
;
1627 /* check reserved area lock */
1628 if (ReservedAreaIsLocked
)
1630 *error
= ERROR_DISK_FULL
;
1635 if (IsVolume(*parent
))
1636 parentnr
= ANODE_ROOTDIR
;
1638 parentnr
= parent
->file
.direntry
->anode
;
1640 /* truncate dirname to 31 characters */
1641 if (!(l
= strlen(dirname
)))
1643 *error
= ERROR_INVALID_COMPONENT_NAME
;
1646 if (l
> FILENAMESIZE
- 1)
1647 dirname
[FILENAMESIZE
- 1] = 0x0;
1649 /* check if object exists */
1650 if (SearchInDir(parentnr
, dirname
, &info
, g
))
1652 *error
= ERROR_OBJECT_EXISTS
;
1656 /* allocate directory entry, fill it. Make fileentry */
1657 if (!MakeDirEntry(ST_USERDIR
, dirname
, entrybuffer
, g
))
1660 if (!AddDirectoryEntry(parent
, (struct direntry
*)entrybuffer
, &info
.file
, g
))
1662 FreeAnode(((struct direntry
*)entrybuffer
)->anode
, g
);
1664 *error
= ERROR_DISK_FULL
;
1668 type
.value
= ET_LOCK
| ET_EXCLREAD
;
1669 if (!(fileentry
= MakeListEntry(&info
, type
, error
, g
)))
1671 if (!AddListEntry(fileentry
)) /* Should never fail, accessconflict impossible */
1673 ErrorMsg(AFS_ERROR_NEWDIR_ADDLISTENTRY
, NULL
, g
);
1677 /* Make first directoryblock (needed for parentfinding) */
1678 if (!(blocknr
= AllocReservedBlock(g
)))
1680 *error
= ERROR_DISK_FULL
;
1682 FreeAnode(info
.file
.direntry
->anode
, g
);
1683 RemoveDirEntry(info
.file
, g
);
1685 FreeListEntry(fileentry
, g
);
1686 DB(Trace(1, "Newdir", "disk full"));
1690 blk
= MakeDirBlock(blocknr
, info
.file
.direntry
->anode
,
1691 info
.file
.direntry
->anode
, parentnr
, g
);
1692 (void)blk
; // Unused
1694 return (lockentry_t
*)fileentry
;
1697 struct cdirblock
*MakeDirBlock(ULONG blocknr
, ULONG anodenr
, ULONG rootanodenr
,
1698 ULONG parentnr
, globaldata
* g
)
1700 struct canode anode
;
1701 struct cdirblock
*blk
;
1702 struct volumedata
*volume
= g
->currentvolume
;
1704 DB(Trace(10,"MakeDirBlock","blocknr = %lx\n", blocknr
));
1706 /* fill in anode (allocated by MakeDirEntry) */
1707 anode
.clustersize
= 1;
1708 anode
.blocknr
= blocknr
;
1710 SaveAnode(&anode
, anodenr
, g
);
1712 blk
= (struct cdirblock
*)AllocLRU(g
);
1713 blk
->blk
.id
= DBLKID
;
1714 blk
->blk
.anodenr
= rootanodenr
;
1715 blk
->blk
.parent
= parentnr
;
1716 blk
->volume
= volume
;
1717 blk
->blocknr
= blocknr
;
1718 blk
->oldblocknr
= 0;
1719 blk
->changeflag
= TRUE
;
1721 Hash(blk
, volume
->dirblks
, HASHM_DIR
);
1731 * - The object referenced by the info structure is removed
1732 * - The object must be on currentvolume
1736 * - check deleteprotection
1737 * - if dir, check if directory is empty
1738 * - check if there are outstanding locks on object
1739 * - remove object from directory and free anode
1740 * - rearrange & store directory
1742 * Don't check dirtycount!
1743 * info becomes INVALID!
1745 BOOL
DeleteObject(union objectinfo
* info
, SIPTR
*error
, globaldata
* g
)
1749 ENTER("DeleteObject");
1750 /* Check deleteprotection */
1752 if (!info
|| info
->deldir
.special
<= SPECIAL_DELFILE
||
1753 info
->file
.direntry
->protection
& FIBF_DELETE
)
1755 if (!info
|| IsVolume(*info
) || info
->file
.direntry
->protection
& FIBF_DELETE
)
1758 *error
= ERROR_DELETE_PROTECTED
;
1762 /* Check if link, links can always be removed */
1763 if ((info
->file
.direntry
->type
== ST_LINKFILE
) ||
1764 (info
->file
.direntry
->type
== ST_LINKDIR
))
1766 return DeleteLink(&info
->file
, error
, g
);
1769 anodenr
= FIANODENR(&info
->file
);
1771 /* Check if there are outstanding locks on object */
1772 if (ScanLockList(HeadOf(&g
->currentvolume
->fileentries
), anodenr
))
1774 DB(Trace(1, "Delete", "object in use"));
1775 *error
= ERROR_OBJECT_IN_USE
;
1779 /* Check if object has links,
1780 * if it does the object should not be deleted,
1783 if (!RemapLinks(&info
->file
, g
))
1785 /* Remove object from directory and free anode */
1786 if (info
->file
.direntry
->type
== ST_USERDIR
)
1787 return DeleteDir(info
, error
, g
);
1790 /* ST_FILE or ST_SOFTLINK */
1791 struct anodechain
*achain
;
1792 int do_deldir
= g
->deldirenabled
&& info
->file
.direntry
->type
== ST_FILE
;
1795 if (!(achain
= GetAnodeChain(anodenr
, g
)))
1797 *error
= ERROR_NO_FREE_STORE
;
1802 ddslot
= AllocDeldirSlot(g
);
1803 AddToDeldir(info
, ddslot
, g
);
1806 ChangeDirEntry(info
->file
, NULL
, NULL
, NULL
, g
); /* remove direntry */
1808 FreeBlocksAC(achain
, UINT_MAX
, keepanodes
, g
);
1811 FreeBlocksAC(achain
, UINT_MAX
, freeanodes
, g
);
1812 FreeAnode(achain
->head
.an
.nr
, g
);
1814 DetachAnodeChain(achain
, g
);
1824 static BOOL
DeleteDir(union objectinfo
*info
, SIPTR
*error
, globaldata
* g
)
1826 struct canode anode
, chnode
;
1827 struct volumedata
*volume
= g
->currentvolume
;
1828 struct cdirblock
*dirblk
;
1831 anode
.nr
= FIANODENR(&info
->file
);
1832 if (!DirIsEmpty(anode
.nr
, g
))
1834 *error
= ERROR_DIRECTORY_NOT_EMPTY
;
1839 /* check if tobefreedcache is sufficiently large,
1840 * otherwise update disk
1842 chnode
.next
= anode
.nr
;
1843 for (t
=1; chnode
.next
; t
++)
1844 GetAnode(&chnode
, chnode
.next
, g
);
1846 if (2*t
+ alloc_data
.rtbf_index
> RTBF_THRESHOLD
)
1849 /* do it (btw: fails if dirblock contains more than 128 empty
1852 anode
.next
= anode
.nr
;
1855 GetAnode(&anode
, anode
.next
, g
);
1857 /* remove dirblock from list if there */
1858 dirblk
= (struct cdirblock
*)CheckCache(volume
->dirblks
, HASHM_DIR
, anode
.blocknr
, g
);
1862 if (dirblk
->changeflag
)
1863 ResToBeFreed(dirblk
->oldblocknr
, g
);
1865 FreeLRU((struct cachedblock
*)dirblk
);
1867 FreeAnode(anode
.nr
, g
);
1868 ResToBeFreed(anode
.blocknr
, g
);
1870 ChangeDirEntry(info
->file
, NULL
, NULL
, NULL
, g
); // delete entry from parentdir
1876 * AFS Temporary extensions: kill empty, remove dir entry
1878 BOOL
KillEmpty(union objectinfo
* parent
, globaldata
* g
)
1882 union objectinfo filefi
;
1884 if (IsVolume(*parent
))
1885 dirnodenr
= ANODE_ROOTDIR
;
1887 dirnodenr
= parent
->file
.direntry
->anode
;
1889 if (SearchInDir(dirnodenr
, "", &filefi
, g
) && IsDir(filefi
))
1890 return DeleteDir(&filefi
, &error
, g
);
1896 * Remove a directory entry without freeing anything and without
1899 LONG
forced_RemoveDirEntry(union objectinfo
*info
, SIPTR
*error
, globaldata
* g
)
1901 if (!info
|| IsVolume(*info
))
1903 *error
= ERROR_DELETE_PROTECTED
;
1907 ChangeDirEntry(info
->file
, NULL
, NULL
, NULL
, g
); /* rearrange & store done by this function */
1911 /* Check if directory with anodenr [anodenr] is empty
1912 * There can be multiple empty directory blocks
1914 static BOOL
DirIsEmpty(ULONG anodenr
, globaldata
* g
)
1916 struct canode anode
;
1917 struct cdirblock
*dirblok
;
1919 GetAnode(&anode
, anodenr
, g
);
1920 dirblok
= LoadDirBlock(anode
.blocknr
, g
);
1922 while (dirblok
&& (dirblok
->blk
.entries
[0] == 0) && anode
.next
)
1924 GetAnode(&anode
, anode
.next
, g
);
1925 dirblok
= LoadDirBlock(anode
.blocknr
, g
);
1928 if (dirblok
&& ((dirblok
->blk
.entries
[0]) == 0)) /* not empty->entries present */
1936 * Frees anodes without freeing blocks
1938 void FreeAnodesInChain(ULONG anodenr
, globaldata
* g
)
1940 struct canode anode
;
1941 struct crootblockextension
*rext
= g
->currentvolume
->rblkextension
;
1943 DB(Trace(1, "FreeAnodeInChain", "anodenr: %ld \n", anodenr
));
1944 GetAnode(&anode
, anodenr
, g
);
1945 while (anode
.nr
) /* stops autom.: anode.nr of anode 0 == 0 */
1947 if (IsUpdateNeeded(RTBF_THRESHOLD
))
1951 rext
->blk
.tobedone
.operation_id
= PP_FREEANODECHAIN
;
1952 rext
->blk
.tobedone
.argument1
= anode
.nr
;
1953 rext
->blk
.tobedone
.argument2
= 0;
1954 rext
->blk
.tobedone
.argument3
= 0;
1960 FreeAnode(anode
.nr
, g
);
1961 GetAnode(&anode
, anode
.next
, g
);
1966 rext
->blk
.tobedone
.operation_id
= 0;
1967 rext
->blk
.tobedone
.argument1
= 0;
1968 rext
->blk
.tobedone
.argument2
= 0;
1969 rext
->blk
.tobedone
.argument3
= 0;
1975 /**********************************************************************/
1976 /* DIRECTORYOPERATIONS */
1977 /* DIRECTORYOPERATIONS */
1978 /* DIRECTORYOPERATIONS */
1979 /**********************************************************************/
1986 * - renaming directories into a child not allowed!
1988 * Rename across devices tested in dd_Rename (DosToHandlerInterface)
1993 * - check if new name allowed
1994 * - destination maken
1995 * - remove source direntry
1996 * - add destination direntry
1998 * maxneeds: 2 dblk changed, 1 new an : 3 res
2000 * sourcedi = objectinfo of source directory
2001 * destdi = objectinfo of destination directory
2002 * srcinfo = objectinfo of source
2003 * destinfo = objectinfo of destination
2004 * src- destanodenr = anodenr of source- destination directory
2006 BOOL
RenameAndMove (union objectinfo
*sourcedi
, union objectinfo
*srcinfo
,
2007 union objectinfo
*destdir
, STRPTR destpath
, SIPTR
*error
,
2010 struct direntry
*srcdirentry
, *destentry
;
2011 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
2012 ULONG srcanodenr
, destanodenr
;
2013 WORD srcfieldoffset
, destfieldoffset
, fieldsize
;
2014 union objectinfo destinfo
, destdi
;
2015 UBYTE
*srccomment
, *destcomment
;
2018 /* fetch source info & path and check if exists */
2019 if (!(destname
= GetFullPath (destdir
, destpath
, &destdi
, error
, g
)))
2021 *error
= ERROR_OBJECT_NOT_FOUND
;
2025 /* source nor destination may be a volume */
2026 if (IsVolume(*srcinfo
) || !*destname
)
2028 *error
= ERROR_OBJECT_WRONG_TYPE
;
2033 if (IsDelDir(*sourcedi
) || IsDelDir(destdi
) || IsDelDir(*srcinfo
))
2035 *error
= ERROR_WRITE_PROTECTED
;
2040 /* check reserved area lock */
2041 if (ReservedAreaIsLocked
)
2043 *error
= ERROR_DISK_FULL
;
2047 srcdirentry
= srcinfo
->file
.direntry
;
2048 srccomment
= COMMENT(srcdirentry
);
2050 /* check if new name allowed
2051 * destpath should exist and file should not
2052 * %9.1 the same name IS allowed (rename 'hello' to 'Hello')
2054 if (FindObject(&destdi
, destname
, &destinfo
, error
, g
))
2056 if (destinfo
.file
.direntry
!= srcinfo
->file
.direntry
)
2058 *error
= ERROR_OBJECT_EXISTS
;
2063 /* Test if a directory is being renamed to a child of itself. This is so
2065 * 1) source (srcinfo) is a directory and
2066 * 2) sourcepath (sourcedi) <> destinationpath (destdi) and
2067 * 3) source (srcinfo) is part of destpath (destdi)
2068 * Example: rename a/b to a/b/c/d:
2069 * 1) a/b is dir [ok]; 2) a <> a/b/c [ok]; 3) a/b is part of a/b/c [ok]
2070 * Links need special attention!
2072 srcanodenr
= IsRootA(*sourcedi
) ? ANODE_ROOTDIR
: FIANODENR(&sourcedi
->file
);
2073 destanodenr
= IsRootA(destdi
) ? ANODE_ROOTDIR
: FIANODENR(&destdi
.file
);
2074 if (IsRealDir(*srcinfo
) && (srcanodenr
!= destanodenr
) &&
2075 IsChildOf(destdi
, *srcinfo
, g
))
2077 *error
= ERROR_OBJECT_IN_USE
;
2081 /* Make destination */
2082 destentry
= (struct direntry
*)&entrybuffer
;
2085 memcpy(destentry
, srcdirentry
, offsetof(struct direntry
, nlength
));
2088 destentry
->nlength
= (UBYTE
)strlen(destname
);
2089 if (destentry
->nlength
> FILENAMESIZE
- 1)
2090 destentry
->nlength
= FILENAMESIZE
- 1;
2091 memcpy((UBYTE
*)&destentry
->startofname
, destname
, destentry
->nlength
);
2094 destcomment
= (UBYTE
*)&destentry
->startofname
+ destentry
->nlength
;
2095 memcpy(destcomment
, srccomment
, *srccomment
+ 1);
2098 srcfieldoffset
= (sizeof(struct direntry
) + srcdirentry
->nlength
+ *srccomment
) & 0xfffe;
2099 destfieldoffset
= (sizeof(struct direntry
) + strlen(destname
) + *srccomment
) & 0xfffe;
2100 fieldsize
= srcdirentry
->next
- srcfieldoffset
;
2101 if (g
->dirextension
)
2102 memcpy((UBYTE
*)destentry
+ destfieldoffset
, (UBYTE
*)srcdirentry
+ srcfieldoffset
, fieldsize
);
2105 if (g
->dirextension
)
2106 destentry
->next
= (UBYTE
)(destfieldoffset
+ fieldsize
);
2108 destentry
->next
= (UBYTE
)destfieldoffset
;
2110 /* remove source and add new direntry
2111 * Makes srcinfo INVALID
2113 PFSDoNotify(&srcinfo
->file
, TRUE
, g
);
2114 ChangeDirEntry(srcinfo
->file
, destentry
, &destdi
, &destinfo
.file
, g
); // output:destinfo
2116 /* Update linklist and notify source if object moved across dirs
2118 if (destanodenr
!= srcanodenr
)
2120 MoveLink (destentry
, destanodenr
, g
);
2121 PFSDoNotify (&destinfo
.file
, TRUE
, g
);
2125 PFSDoNotify (&destinfo
.file
, FALSE
, g
);
2128 /* If object is a directory and parent changed, update dirblocks */
2129 if (IsDir(destinfo
) && (srcanodenr
!= destanodenr
))
2131 struct canode anode
;
2135 anode
.nr
= destinfo
.file
.direntry
->anode
;
2137 GetAnode (&anode
, anode
.nr
, g
);
2138 for (anodeoffset
= 0; gadoor
; gadoor
= NextBlock (&anode
, &anodeoffset
, g
))
2140 struct cdirblock
*blk
;
2142 blk
= LoadDirBlock (anode
.blocknr
+ anodeoffset
, g
);
2145 blk
->blk
.parent
= destanodenr
; // destination dir
2146 MakeBlockDirty ((struct cachedblock
*)blk
, g
);
2157 * - get old direntry
2158 * - make new direntry
2159 * - remove old direntry
2160 * - add new direntry
2162 * maxdirty: 1d, 1a = 2 res
2164 BOOL
AddComment(union objectinfo
* info
, STRPTR comment
, SIPTR
*error
, globaldata
* g
)
2166 struct direntry
*sourceentry
, *destentry
;
2167 union objectinfo directory
;
2168 UBYTE
*destcomment
, *srccomment
, entrybuffer
[MAX_ENTRYSIZE
];
2169 WORD srcfieldoffset
, destfieldoffset
, fieldsize
;
2171 DB(Trace(1, "AddComment", "%s\n", comment
));
2173 if (info
->deldir
.special
<= SPECIAL_DELFILE
)
2175 *error
= ERROR_WRITE_PROTECTED
;
2180 if (strlen(comment
) > CMSIZE
)
2182 *error
= ERROR_COMMENT_TOO_BIG
;
2186 /* check reserved area lock */
2187 if (ReservedAreaIsLocked
)
2189 *error
= ERROR_DISK_FULL
;
2193 /* make new direntry */
2194 destentry
= (struct direntry
*)entrybuffer
;
2195 sourceentry
= info
->file
.direntry
;
2197 /* copy header & name */
2198 memcpy(destentry
, sourceentry
, sizeof(struct direntry
) + sourceentry
->nlength
- 1);
2201 destcomment
= COMMENT(destentry
);
2202 *destcomment
= strlen(comment
);
2203 memcpy(destcomment
+ 1, comment
, *destcomment
);
2206 srccomment
= COMMENT(sourceentry
);
2207 srcfieldoffset
= (sizeof(struct direntry
) + sourceentry
->nlength
+ *srccomment
) & 0xfffe;
2208 destfieldoffset
= (sizeof(struct direntry
) + sourceentry
->nlength
+ *destcomment
) & 0xfffe;
2209 fieldsize
= sourceentry
->next
- srcfieldoffset
;
2210 if (g
->dirextension
)
2211 memcpy((UBYTE
*)destentry
+ destfieldoffset
, (UBYTE
*)sourceentry
+ srcfieldoffset
, fieldsize
);
2214 if (g
->dirextension
)
2215 destentry
->next
= (UBYTE
)(destfieldoffset
+ fieldsize
);
2217 destentry
->next
= (UBYTE
)destfieldoffset
;
2219 /* remove old directoryentry and add new */
2220 if (!GetParent(info
, &directory
, error
, g
))
2224 ChangeDirEntry(info
->file
, destentry
, &directory
, &info
->file
, g
);
2229 /* ProtectFile, SetDate
2231 * - simple direntry in cache change, no change in size
2232 * - CACHEDDIRENTRY must have changeflag
2234 * maxneeds: changes 1 block. NEVER allocates new block
2236 BOOL
ProtectFile(struct fileinfo
* file
, ULONG protection
, SIPTR
*error
, globaldata
* g
)
2238 ENTER("ProtectFile");
2240 // isvolume check already done in dostohandler..
2242 // if (!file || !file->direntry) /* @XLV */
2244 // *error = ERROR_OBJECT_WRONG_TYPE;
2249 if ((*(union objectinfo
*)file
).delfile
.special
<= SPECIAL_DELFILE
)
2251 if ((*(union objectinfo
*)file
).delfile
.special
== SPECIAL_DELDIR
)
2253 protection
&= DELENTRY_PROT_AND_MASK
;
2254 protection
|= DELENTRY_PROT_OR_MASK
;
2255 g
->currentvolume
->rblkextension
->blk
.dd_protection
= protection
;
2256 MakeBlockDirty((struct cachedblock
*)g
->currentvolume
->rblkextension
, g
);
2260 *error
= ERROR_WRITE_PROTECTED
;
2265 /* check reserved area lock */
2266 if (ReservedAreaIsLocked
)
2268 *error
= ERROR_DISK_FULL
;
2272 file
->direntry
->protection
= protection
;
2274 /* add second part of protection */
2275 if (g
->dirextension
)
2277 union objectinfo directory
;
2278 struct direntry
*sourceentry
, *destentry
;
2279 struct extrafields extrafields
;
2280 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
2282 /* make new direntry */
2283 destentry
= (struct direntry
*)entrybuffer
;
2284 sourceentry
= file
->direntry
;
2287 memcpy(destentry
, sourceentry
, sourceentry
->next
);
2289 /* set new extrafields */
2290 GetExtraFields(sourceentry
, &extrafields
);
2291 extrafields
.prot
= protection
;
2292 AddExtraFields(destentry
, &extrafields
);
2294 /* commit changes */
2295 if (!GetParent((union objectinfo
*)file
, &directory
, error
, g
))
2298 ChangeDirEntry(*file
, destentry
, &directory
, file
, g
);
2301 /* mark block for update and return success */
2302 MakeBlockDirty((struct cachedblock
*)file
->dirblock
, g
);
2306 BOOL
SetOwnerID(struct fileinfo
* file
, ULONG owner
, SIPTR
*error
, globaldata
* g
)
2308 struct extrafields extrafields
;
2309 union objectinfo directory
;
2310 struct direntry
*sourceentry
, *destentry
;
2311 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
2313 ENTER("SetOwnerID");
2315 if ((*(union objectinfo
*)file
).delfile
.special
<= SPECIAL_DELFILE
)
2317 if ((*(union objectinfo
*)file
).delfile
.special
== SPECIAL_DELDIR
)
2319 struct crootblockextension
*rext
= g
->currentvolume
->rblkextension
;
2321 rext
->blk
.dd_uid
= owner
>> 16;
2322 rext
->blk
.dd_gid
= owner
& 0xffff;
2323 MakeBlockDirty ((struct cachedblock
*)rext
, g
);
2327 *error
= ERROR_WRITE_PROTECTED
;
2332 if (!g
->dirextension
)
2334 *error
= ERROR_ACTION_NOT_KNOWN
;
2338 /* check reserved area lock */
2339 if (ReservedAreaIsLocked
)
2341 *error
= ERROR_DISK_FULL
;
2345 /* make new direntry */
2346 destentry
= (struct direntry
*)entrybuffer
;
2347 sourceentry
= file
->direntry
;
2350 memcpy(destentry
, sourceentry
, sourceentry
->next
);
2352 /* set new extrafields */
2353 GetExtraFields(sourceentry
, &extrafields
);
2354 extrafields
.uid
= owner
>> 16;
2355 extrafields
.gid
= owner
& 0xffff;
2356 AddExtraFields(destentry
, &extrafields
);
2358 /* commit changes */
2359 if (!GetParent((union objectinfo
*)file
, &directory
, error
, g
))
2362 ChangeDirEntry(*file
, destentry
, &directory
, file
, g
);
2364 MakeBlockDirty((struct cachedblock
*)file
->dirblock
, g
);
2368 LONG
ReadSoftLink(union objectinfo
*linkfi
, char *buffer
, ULONG size
, SIPTR
*error
, globaldata
* g
)
2370 struct canode anode
;
2371 UBYTE softblock
[1024];
2373 ENTER("ReadSoftLink");
2374 if (!linkfi
|| IsVolume(*linkfi
))
2376 *error
= ERROR_OBJECT_WRONG_TYPE
;
2380 if (linkfi
->file
.direntry
->fsize
+ (g
->unparsed
? strlen(g
->unparsed
) : 0) > size
)
2383 GetAnode(&anode
, linkfi
->file
.direntry
->anode
, g
);
2384 DiskRead(softblock
, 1, anode
.blocknr
, g
);
2385 strcpy(buffer
, softblock
);
2388 strcat(buffer
, g
->unparsed
);
2390 return (LONG
)strlen(buffer
);
2393 BOOL
CreateSoftLink(union objectinfo
*linkdir
, STRPTR linkname
, STRPTR softlink
,
2394 union objectinfo
*newlink
, SIPTR
*error
, globaldata
* g
)
2397 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
2398 struct direntry
*de
;
2399 UBYTE softblock
[1024];
2400 struct canode anode
;
2403 ENTER("CreateSoftLink");
2405 if (IsDelDir(*linkdir
))
2407 *error
= ERROR_WRITE_PROTECTED
;
2412 /* check disk-writeprotection etc */
2413 if (!CheckVolume(g
->currentvolume
, 1, error
, g
))
2416 /* get anodenr of directory */
2417 if (!linkdir
|| IsVolume(*linkdir
))
2418 anodenr
= ANODE_ROOTDIR
;
2421 anodenr
= FIANODENR(&linkdir
->file
);
2422 LOCK(linkdir
->file
.dirblock
);
2425 /* truncate filename to 31 characters */
2426 if (!(l
= strlen(linkname
)))
2428 *error
= ERROR_INVALID_COMPONENT_NAME
;
2431 if (l
> FILENAMESIZE
- 1)
2432 linkname
[FILENAMESIZE
- 1] = 0x0;
2434 /* check reserved area lock */
2435 if (ReservedAreaIsLocked
)
2437 *error
= ERROR_DISK_FULL
;
2441 /* check if a file by that name already exists */
2442 if (SearchInDir(anodenr
, linkname
, newlink
, g
))
2444 *error
= ERROR_OBJECT_EXISTS
;
2448 /* make directory entry
2449 * the anode allocated is the link list element
2451 de
= (struct direntry
*)entrybuffer
;
2452 if (!MakeDirEntry(ST_SOFTLINK
, linkname
, entrybuffer
, g
))
2455 /* store directoryentry */
2456 if (!AddDirectoryEntry(linkdir
, (struct direntry
*)entrybuffer
, &newlink
->file
, g
))
2459 /* fill directory entry */
2460 if (!(AllocateBlocks(de
->anode
, 1, g
)))
2462 *error
= ERROR_DISK_FULL
;
2466 GetAnode(&anode
, de
->anode
, g
);
2467 memset(softblock
, 0, 1024);
2468 strcpy(softblock
, softlink
);
2469 DiskWrite(softblock
, 1, anode
.blocknr
, g
);
2470 newlink
->file
.direntry
->fsize
= strlen(softblock
);
2475 RemoveDirEntry(newlink
->file
, g
);
2477 FreeAnode(de
->anode
, g
);
2482 * linkdir: directory (in)
2483 * linkname: name (in)
2484 * object: object to link to (in) (dir must be locked)
2485 * newlink: result (out)
2487 BOOL
CreateLink(union objectinfo
* linkdir
, STRPTR linkname
, union objectinfo
* object
,
2488 union objectinfo
* newlink
, SIPTR
*error
, globaldata
* g
)
2490 union objectinfo info
, odi
;
2491 ULONG anodenr
, linklist
;
2492 struct direntry
*objectentry
, *destentry
;
2493 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
2494 struct extrafields extrafields
;
2495 struct canode linknode
;
2498 ENTER("CreateLink");
2500 if (IsDelDir(*linkdir
) || IsDelDir(*object
) || IsDelFile(*object
))
2502 *error
= ERROR_WRITE_PROTECTED
;
2507 /* check if operation possible */
2508 if (!g
->dirextension
)
2510 *error
= ERROR_ACTION_NOT_KNOWN
;
2514 /* check disk-writeprotection etc */
2515 if (!CheckVolume(g
->currentvolume
, 1, error
, g
))
2519 if (!linkdir
|| IsVolume(*linkdir
))
2521 anodenr
= ANODE_ROOTDIR
;
2525 anodenr
= FIANODENR(&linkdir
->file
);
2526 LOCK(linkdir
->file
.dirblock
);
2529 /* truncate filename to 31 characters */
2530 if (!(l
= strlen(linkname
)))
2532 *error
= ERROR_INVALID_COMPONENT_NAME
;
2535 if (l
> FILENAMESIZE
- 1)
2536 linkname
[FILENAMESIZE
- 1] = 0x0;
2538 /* check reserved area lock */
2539 if (ReservedAreaIsLocked
)
2541 *error
= ERROR_DISK_FULL
;
2545 /* check if a file by that name already exists */
2546 if (SearchInDir(anodenr
, linkname
, &info
, g
))
2548 *error
= ERROR_OBJECT_EXISTS
;
2552 /* make directory entry
2553 * the anode allocated is the link list element
2555 if (!MakeDirEntry(ST_LINKDIR
, linkname
, entrybuffer
, g
))
2559 destentry
= (struct direntry
*)entrybuffer
;
2560 objectentry
= object
->file
.direntry
;
2562 GetExtraFields(destentry
, &extrafields
);
2564 memset(&extrafields
, 0, sizeof(struct extrafields
));
2566 extrafields
.link
= objectentry
->anode
;
2567 AddExtraFields(destentry
, &extrafields
);
2569 /* copy object info */
2570 destentry
->fsize
= objectentry
->fsize
;
2571 switch (objectentry
->type
)
2575 case ST_ROLLOVERFILE
:
2577 destentry
->type
= ST_LINKFILE
;
2581 destentry
->type
= ST_LINKDIR
;
2585 /* store directoryentry */
2586 if (!AddDirectoryEntry(linkdir
, destentry
, &newlink
->file
, g
))
2588 FreeAnode(destentry
->anode
, g
);
2593 linknode
.clustersize
= object
->file
.dirblock
->blk
.anodenr
;
2594 linknode
.blocknr
= newlink
->file
.dirblock
->blk
.anodenr
;
2596 SaveAnode(&linknode
, newlink
->file
.direntry
->anode
, g
);
2598 /* change objectentry */
2599 GetExtraFields(objectentry
, &extrafields
);
2600 if (!(linklist
= extrafields
.link
))
2602 /* there were no links yet ->
2603 * add link field. Use entrybuffer and destentry pointer
2605 extrafields
.link
= linklist
= newlink
->file
.direntry
->anode
;
2606 memcpy(entrybuffer
, objectentry
, objectentry
->next
);
2607 AddExtraFields(destentry
, &extrafields
);
2609 if (!GetParent(object
, &odi
, error
, g
))
2610 return DOSFALSE
; /* serious! should not happen */
2612 ChangeDirEntry(object
->file
, destentry
, &odi
, &object
->file
, g
);
2616 /* add new link to chain */
2617 GetAnode(&linknode
, extrafields
.link
, g
);
2618 while (linknode
.next
)
2619 GetAnode(&linknode
, linknode
.next
, g
);
2620 linknode
.next
= newlink
->file
.direntry
->anode
;
2621 SaveAnode(&linknode
, linknode
.nr
, g
);
2627 BOOL
SetDate(union objectinfo
*file
, struct DateStamp
*date
, SIPTR
*error
, globaldata
*g
)
2632 if (file
->deldir
.special
<= SPECIAL_DELFILE
)
2634 *error
= ERROR_WRITE_PROTECTED
;
2639 if (!CheckVolume(file
->file
.dirblock
->volume
, 1, error
, g
))
2642 file
->file
.direntry
->creationday
= (UWORD
)date
->ds_Days
;
2643 file
->file
.direntry
->creationminute
= (UWORD
)date
->ds_Minute
;
2644 file
->file
.direntry
->creationtick
= (UWORD
)date
->ds_Tick
;
2645 MakeBlockDirty((struct cachedblock
*)file
->file
.dirblock
, g
);
2649 void Touch(struct fileinfo
*info
, globaldata
* g
) // ook archiveflag..
2651 struct DateStamp time
;
2656 if (IsVolume(*((union objectinfo
*)info
)) &&
2657 g
->currentvolume
->rblkextension
)
2659 g
->currentvolume
->rblkextension
->blk
.root_date
[0] = (UWORD
)time
.ds_Days
;
2660 g
->currentvolume
->rblkextension
->blk
.root_date
[1] = (UWORD
)time
.ds_Minute
;
2661 g
->currentvolume
->rblkextension
->blk
.root_date
[2] = (UWORD
)time
.ds_Tick
;
2662 MakeBlockDirty((struct cachedblock
*)g
->currentvolume
->rblkextension
, g
);
2667 if (!IsVolume(*((union objectinfo
*)info
)))
2669 info
->direntry
->creationday
= (UWORD
)time
.ds_Days
;
2670 info
->direntry
->creationminute
= (UWORD
)time
.ds_Minute
;
2671 info
->direntry
->creationtick
= (UWORD
)time
.ds_Tick
;
2672 info
->direntry
->protection
&= ~FIBF_ARCHIVE
; // clear archivebit (eor)
2674 MakeBlockDirty((struct cachedblock
*)info
->dirblock
, g
);
2681 * dir: directory (in)
2682 * rollname: name of rollover file (in)
2683 * result: created rolloverfile (out)
2685 BOOL
CreateRollover(union objectinfo
*dir
, STRPTR rollname
, ULONG size
,
2686 union objectinfo
*result
, SIPTR
*error
, globaldata
* g
)
2689 struct direntry
*de
;
2690 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
2691 struct anodechain
*ac
;
2694 DB(Trace(1, "CreateRollover", "name %s size %d \n", rollname
, size
));
2696 /* no write access to deldir */
2699 *error
= ERROR_WRITE_PROTECTED
;
2704 /* check if operation possible */
2705 if (!g
->dirextension
)
2707 *error
= ERROR_ACTION_NOT_KNOWN
;
2714 *error
= ERROR_BAD_NUMBER
;
2718 /* check disk-writeprotection etc */
2719 if (!CheckVolume(g
->currentvolume
, 1, error
, g
))
2722 /* get anodenr of directory */
2723 if (!dir
|| IsVolume(*dir
))
2724 anodenr
= ANODE_ROOTDIR
;
2727 anodenr
= FIANODENR(&dir
->file
);
2728 LOCK(dir
->file
.dirblock
);
2731 /* truncate filename to 31 characters */
2732 if (!(l
= strlen(rollname
)))
2734 *error
= ERROR_INVALID_COMPONENT_NAME
;
2737 if (l
> FILENAMESIZE
- 1)
2738 rollname
[FILENAMESIZE
- 1] = 0x0;
2740 /* check reserved area lock */
2741 if (ReservedAreaIsLocked
)
2743 *error
= ERROR_DISK_FULL
;
2747 /* check if a file by that name already exists */
2748 if (SearchInDir(anodenr
, rollname
, result
, g
))
2750 *error
= ERROR_OBJECT_EXISTS
;
2754 /* make directory entry
2755 * the anode allocated is the link list element
2757 de
= (struct direntry
*)entrybuffer
;
2758 if (!MakeDirEntry(ST_ROLLOVERFILE
, rollname
, entrybuffer
, g
))
2761 /* add rollover info is not necessary, since
2762 * both virtualsize and rollpointer are initially
2765 if (!(ac
= GetAnodeChain(de
->anode
, g
)))
2768 /* store directoryentry */
2769 if (!AddDirectoryEntry(dir
, de
, &result
->file
, g
))
2773 * in case of an intermediate update, the rollover file will
2774 * be temporarily committed smaller
2776 if (!(AllocateBlocksAC(ac
, size
, &result
->file
, g
)))
2781 result
->file
.direntry
->fsize
= size
<< BLOCKSHIFT
;
2786 RemoveDirEntry(result
->file
, g
);
2788 DetachAnodeChain(ac
, g
);
2790 FreeAnode(de
->anode
, g
);
2794 /* changes/reads rollover information of rollfile using roinfo. Objectinfo of
2795 * 'rollfile' is updated, if so needed. Roinfo is always filled with the current
2796 * rollfile settings (AFTER update). The real filesize is only changed when the
2797 * realsize fiels is unequal zero.
2799 ULONG
SetRollover(fileentry_t
*rollfile
, struct rolloverinfo
*roinfo
, globaldata
*g
)
2801 union objectinfo directory
;
2802 struct extrafields extrafields
;
2803 struct direntry
*sourcede
, *destde
;
2804 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
2808 /* check if file is rollover file */
2809 if (!IsRollover(rollfile
->le
.info
))
2810 return ERROR_OBJECT_WRONG_TYPE
;
2812 destde
= (struct direntry
*)entrybuffer
;
2813 sourcede
= rollfile
->le
.info
.file
.direntry
;
2814 GetExtraFields(sourcede
, &extrafields
);
2817 if (roinfo
->realsize
)
2819 realsize
= roinfo
->realsize
& ~(BLOCKSIZE
-1);
2820 if (!realsize
) realsize
= BLOCKSIZE
;
2823 realsize
= sourcede
->fsize
;
2825 /* virtualsize and rollpointer can not extend past end
2826 * of file. virtualsize has to be <= realsize - 1
2828 if (roinfo
->rollpointer
> realsize
||
2829 roinfo
->virtualsize
>= realsize
)
2830 return ERROR_SEEK_ERROR
;
2832 if (roinfo
->realsize
)
2833 ChangeFileSize(rollfile
, realsize
, OFFSET_BEGINNING
, &error
, g
);
2834 roinfo
->realsize
= sourcede
->fsize
;
2835 memcpy(destde
, sourcede
, sourcede
->next
);
2836 extrafields
.virtualsize
= roinfo
->virtualsize
;
2837 extrafields
.rollpointer
= roinfo
->rollpointer
;
2838 AddExtraFields(destde
, &extrafields
);
2840 if (!GetParent(&rollfile
->le
.info
, &directory
, &error
, g
))
2843 ChangeDirEntry(rollfile
->le
.info
.file
, destde
, &directory
,
2844 &rollfile
->le
.info
.file
, g
);
2848 roinfo
->realsize
= sourcede
->fsize
;
2849 roinfo
->virtualsize
= extrafields
.virtualsize
;
2850 roinfo
->rollpointer
= extrafields
.rollpointer
;
2856 #endif /* ROLLOVER */
2858 /**********************************************************************/
2859 /* LL CHANGE DIRENTRY */
2860 /* LL CHANGE DIRENTRY */
2861 /* LL CHANGE DIRENTRY */
2862 /**********************************************************************/
2865 /* Change a directoryentry. Covers all reference changing too
2867 * If direntry==NULL no new direntry is to be added, only removed.
2868 * result may be NULL then as well
2870 * in: from, to, destdir
2873 * from can become INVALID..
2876 void ChangeDirEntry(struct fileinfo from
, struct direntry
*to
,
2877 union objectinfo
*destdir
, struct fileinfo
*result
, globaldata
* g
)
2879 ULONG destanodenr
= IsRoot(destdir
) ? ANODE_ROOTDIR
: FIANODENR(&destdir
->file
);
2881 /* check whether a 'within dir' rename */
2882 if (to
&& destanodenr
== from
.dirblock
->blk
.anodenr
)
2883 RenameWithinDir(from
, to
, result
, g
);
2885 RenameAcrossDirs(from
, to
, destdir
, result
, g
);
2889 * Move a file from one dir to another
2890 * NULL = delete allowed
2892 static void RenameAcrossDirs(struct fileinfo from
, struct direntry
*to
,
2893 union objectinfo
*destdir
, struct fileinfo
*result
, globaldata
* g
)
2897 /* remove old entry (invalidates 'destdir') */
2898 removedlen
= from
.direntry
->next
;
2899 RemoveDirEntry(from
, g
);
2902 /* test on volume is not necessary, because file.dirblock = volume.volume !=
2904 * restore 'destdir' (can be invalidated by RemoveDirEntry)
2906 if (destdir
->file
.dirblock
== from
.dirblock
&&
2907 destdir
->file
.direntry
> from
.direntry
)
2909 destdir
->file
.direntry
= (struct direntry
*)
2910 ((UBYTE
*)destdir
->file
.direntry
- removedlen
);
2914 AddDirectoryEntry(destdir
, to
, result
, g
);
2917 UpdateChangedRef(from
, result
, -removedlen
, g
);
2919 LOCK(result
->dirblock
);
2923 * Rename file within dir
2924 * NULL destination not allowed
2926 static void RenameWithinDir(struct fileinfo from
, struct direntry
*to
,
2927 struct fileinfo
*result
, globaldata
* g
)
2930 struct fileinfo mover
;
2932 LOCK(from
.dirblock
);
2933 mover
.direntry
= FIRSTENTRY(from
.dirblock
);
2934 mover
.dirblock
= from
.dirblock
;
2935 spaceneeded
= to
->next
- from
.direntry
->next
;
2936 if (spaceneeded
<= 0)
2937 RenameInPlace(from
, to
, result
, g
);
2940 /* make space in block
2942 while (!CheckFit(from
.dirblock
, spaceneeded
, g
) && from
.direntry
!= mover
.direntry
)
2944 from
.direntry
= (struct direntry
*)((UBYTE
*)from
.direntry
- mover
.direntry
->next
);
2945 MoveToPrevious(mover
, mover
.direntry
, result
, g
);
2948 if (CheckFit(from
.dirblock
, spaceneeded
, g
))
2949 RenameInPlace(from
, to
, result
, g
);
2951 MoveToPrevious(from
, to
, result
, g
);
2954 LOCK(result
->dirblock
);
2960 * Check if direntry will fit in,
2961 * returns position to place it if ok
2963 static struct direntry
*CheckFit(struct cdirblock
*blok
, int needed
, globaldata
* g
)
2965 struct direntry
*entry
;
2968 /* goto end of dirblock */
2969 entry
= FIRSTENTRY(blok
);
2970 for (i
= 0; entry
->next
; entry
= NEXTENTRY(entry
))
2973 if (needed
+ i
+ 1 <= DB_ENTRYSPACE
)
2980 * Moves firstentry to previous block, changing it to to. To can point to de.direntry
2982 * Return new fileinfo in 'result'
2983 * NB: no need to touch parent: MTP is always followed by another function
2986 static BOOL
MoveToPrevious(struct fileinfo de
, struct direntry
*to
, struct fileinfo
*result
, globaldata
* g
)
2988 struct direntry
*dest
;
2989 struct cdirblock
*prevblock
;
2990 struct canode anode
;
2996 /* get previous block */
2997 GetAnode(&anode
, de
.dirblock
->blk
.anodenr
, g
);
2999 while (anode
.blocknr
!= de
.dirblock
->blocknr
&& anode
.next
)
3002 GetAnode(&anode
, anode
.next
, g
);
3006 if (anode
.blocknr
!= de
.dirblock
->blocknr
)
3008 ErrorMsg(AFS_ERROR_CACHE_INCONSISTENCY
, NULL
, g
);
3012 /* Get dirblock in question
3013 * Special case : previous == 0!!->add new head!!
3017 GetAnode(&anode
, prev
, g
);
3018 if (!(prevblock
= LoadDirBlock(anode
.blocknr
, g
)))
3023 if (prev
&& (dest
= CheckFit(prevblock
, to
->next
, g
)))
3025 memcpy(dest
, to
, to
->next
);
3026 *(UBYTE
*)NEXTENTRY(dest
) = 0; /* end of dirblock */
3027 result
->direntry
= dest
;
3028 result
->dirblock
= prevblock
;
3032 /* make new dirblock .. */
3034 struct canode newanode
;
3035 struct cdirblock
*newblock
;
3037 newanode
.clustersize
= 1;
3038 parent
= de
.dirblock
->blk
.parent
;
3039 if (!(newanode
.blocknr
= AllocReservedBlock(g
)))
3044 GetAnode(&anode
, de
.dirblock
->blk
.anodenr
, g
);
3045 newanode
.nr
= anode
.nr
;
3046 newanode
.next
= anode
.nr
= AllocAnode (anode
.next
? anode
.next
: anode
.nr
, g
);
3050 newanode
.nr
= AllocAnode (anode
.nr
, g
);
3051 newanode
.next
= anode
.next
;
3052 anode
.next
= newanode
.nr
;
3055 SaveAnode(&anode
, anode
.nr
, g
);
3056 newblock
= MakeDirBlock(newanode
.blocknr
, newanode
.nr
, de
.dirblock
->blk
.anodenr
, parent
, g
);
3057 SaveAnode(&newanode
, newanode
.nr
, g
); /* MUST be done AFTER MakeDirBlock */
3060 dest
= FIRSTENTRY(newblock
);
3061 memcpy(dest
, to
, to
->next
);
3062 *(UBYTE
*)NEXTENTRY(dest
) = 0; /* end of dirblock */
3063 result
->direntry
= dest
;
3064 result
->dirblock
= newblock
;
3067 LOCK(result
->dirblock
);
3068 MakeBlockDirty((struct cachedblock
*)result
->dirblock
, g
);
3070 /* remove old entry & make blocks dirty */
3071 removedlen
= de
.direntry
->next
;
3072 RemoveDirEntry(de
, g
);
3074 /* update references */
3075 UpdateChangedRef(de
, result
, -removedlen
, g
);
3080 * There HAS to be sufficient space!!
3082 static void RenameInPlace(struct fileinfo from
, struct direntry
*to
, struct fileinfo
*result
, globaldata
* g
)
3084 UBYTE
*dest
, *start
, *end
;
3088 union objectinfo parent
;
3090 LOCK(from
.dirblock
);
3092 /* change date parent */
3093 if (GetParent((union objectinfo
*)&from
, &parent
, &error
, g
))
3094 Touch(&parent
.file
, g
);
3096 /* make place for new entry */
3097 diff
= to
->next
- from
.direntry
->next
;
3098 dest
= (UBYTE
*)from
.direntry
+ to
->next
;
3099 start
= (UBYTE
*)from
.direntry
+ from
.direntry
->next
;
3100 end
= (UBYTE
*)&(from
.dirblock
->blk
) + g
->rootblock
->reserved_blksize
;
3101 movelen
= (diff
> 0) ? (end
- dest
) : (end
- start
);
3102 memmove(dest
, start
, movelen
);
3104 /* fill in new entry */
3105 memcpy((UBYTE
*)from
.direntry
, to
, to
->next
);
3107 /* fill in result and make block dirty */
3109 MakeBlockDirty((struct cachedblock
*)from
.dirblock
, g
);
3111 /* update references */
3112 UpdateChangedRef(from
, result
, diff
, g
);
3117 * Simply shift the directryentry out with memmove(dest, src, len)
3118 * References are not corrected (see changedirentry)
3120 * makes all fileinfo's in same block invalid !!
3122 static void RemoveDirEntry(struct fileinfo info
, globaldata
* g
)
3124 UBYTE
*endofblok
, *startofblok
, *destofblok
, *startofclear
;
3127 union objectinfo parent
;
3129 LOCK(info
.dirblock
);
3131 /* change date parent %6.5 */
3132 if (GetParent((union objectinfo
*)&info
, &parent
, &error
, g
))
3133 Touch(&parent
.file
, g
);
3135 /* remove direntry */
3136 destofblok
= (UBYTE
*)info
.direntry
;
3137 startofblok
= destofblok
+ info
.direntry
->next
;
3138 endofblok
= (UBYTE
*)&(info
.dirblock
->blk
) + g
->rootblock
->reserved_blksize
;
3139 startofclear
= endofblok
- info
.direntry
->next
;
3140 clearlen
= info
.direntry
->next
;
3141 memmove(destofblok
, startofblok
, endofblok
- startofblok
);
3143 /* makes info invalid!! */
3144 if (info
.direntry
->next
)
3145 memset(startofclear
, 0, clearlen
);
3146 MakeBlockDirty((struct cachedblock
*)info
.dirblock
, g
); // %6.2
3151 /* AddDirectoryEntry
3153 * Add a directoryentry to a directory.
3154 * Tries to add the directoryentry at the end of an existing directoryblock. If
3155 * that fails, create a new one.
3157 * Operates on currentvolume
3159 * input : - dir: directory to add directoryentry too
3160 * - newentry: the new directoryentry
3162 * output: - newinfo: pointer to direntry and directoryblock the entry
3165 * NB: A) there should ALWAYS be at least one dirblock
3166 * B) assumes CURRENTVOLUME
3168 static BOOL
AddDirectoryEntry(union objectinfo
*dir
, struct direntry
*newentry
,
3169 struct fileinfo
*newinfo
, globaldata
* g
)
3171 struct canode anode
;
3172 ULONG anodeoffset
= 0, diranodenr
;
3173 struct cdirblock
*blok
;
3174 struct direntry
*entry
= NULL
;
3175 BOOL done
= FALSE
, eof
= FALSE
;
3178 if (!dir
|| IsVolume(*dir
))
3179 diranodenr
= ANODE_ROOTDIR
;
3181 diranodenr
= dir
->file
.direntry
->anode
;
3183 /* check if space in existing dirblocks */
3184 for (GetAnode(&anode
, diranodenr
, g
); !done
&& !eof
; eof
= !NextBlock(&anode
, &anodeoffset
, g
))
3186 if (!(blok
= LoadDirBlock(anode
.blocknr
+ anodeoffset
, g
)))
3189 entry
= (struct direntry
*)&blok
->blk
.entries
;
3191 /* goto end of dirblock; i = aantal gebruikte bytes */
3192 for (i
= 0; entry
->next
; entry
= NEXTENTRY(entry
))
3195 /* does it fit in this block? (keep space for trailing 0) */
3196 if (i
+ newentry
->next
+ 1 < DB_ENTRYSPACE
)
3198 memcpy(entry
, newentry
, newentry
->next
);
3199 *(UBYTE
*)NEXTENTRY(entry
) = 0; // dirblock afsluiten
3206 /* no->new dirblock (eof <=> anode is end of chain)
3207 * We will make the new dirblock at the >start< of
3209 * We always allocate new anode
3214 struct canode newanode
;
3216 newanode
.clustersize
= 1;
3217 parent
= blok
->blk
.parent
;
3218 if (!(newanode
.blocknr
= AllocReservedBlock(g
)))
3220 GetAnode (&anode
, diranodenr
, g
);
3221 newanode
.nr
= diranodenr
;
3222 newanode
.next
= anode
.nr
= AllocAnode (anode
.next
? anode
.next
: anode
.nr
, g
);
3223 SaveAnode(&anode
, anode
.nr
, g
);
3224 blok
= MakeDirBlock (newanode
.blocknr
, newanode
.nr
, diranodenr
, parent
, g
);
3225 SaveAnode (&newanode
, newanode
.nr
, g
);
3226 entry
= (struct direntry
*)&blok
->blk
.entries
;
3227 memcpy(entry
, newentry
, newentry
->next
);
3228 *(UBYTE
*)NEXTENTRY(entry
) = 0; // mark end of dirblock
3233 newinfo
->direntry
= entry
;
3234 newinfo
->dirblock
= blok
;
3237 PFSUpdateNotify(blok
->blk
.anodenr
, &entry
->nlength
, entry
->anode
, g
);
3241 MakeBlockDirty((struct cachedblock
*)blok
, g
);
3244 Touch(&dir
->file
, g
);
3251 * diff is direntry size difference (new - original)
3253 static void UpdateChangedRef(struct fileinfo from
, struct fileinfo
*to
, int diff
, globaldata
* g
)
3255 struct volumedata
*volume
= from
.dirblock
->volume
;
3258 for (fe
= HeadOf(&volume
->fileentries
); fe
->next
; fe
= fe
->next
)
3260 /* only dirs and files can be in a directory, but the volume *
3261 * of volumeinfos can never point to a cached block, so a
3262 * type != ETF_VOLUME check is not necessary. Just check the
3265 if (fe
->info
.file
.dirblock
== from
.dirblock
)
3267 /* is het de targetentry ? */
3268 if (fe
->info
.file
.direntry
== from
.direntry
)
3271 fe
->info
.file
= *to
;
3275 /* take only entries after target */
3276 if (fe
->info
.file
.direntry
> from
.direntry
)
3278 fe
->info
.file
.direntry
= (struct direntry
*)
3279 ((UBYTE
*)fe
->info
.file
.direntry
+ diff
);
3284 /* check for exnext references */
3285 if (fe
->type
.flags
.dir
)
3287 lockentry_t
*dle
= (lockentry_t
*)fe
;
3289 if (dle
->nextentry
.dirblock
== from
.dirblock
)
3291 if ((dle
->nextentry
.direntry
== from
.direntry
)
3292 && (!dle
->nextentry
.direntry
->next
))
3294 GetNextEntry(dle
, g
);
3298 /* take only entries after target */
3299 if (dle
->nextentry
.direntry
> from
.direntry
)
3301 dle
->nextentry
.direntry
= (struct direntry
*)
3302 ((UBYTE
*)dle
->nextentry
.direntry
+ diff
);
3313 * Used by L2.NewFile, L2.NewDir
3315 * Make a new directoryentry. The filename is not checked. Allocates anode
3319 * - type: ST_FILE, ST_DIR etc ..
3320 * - name: objectname
3321 * - entrybuffer: place to put direntry (char buffer of size MAX_ENTRYSIZE)
3323 * output: - info: objectinfo of new directoryentry
3325 static BOOL
MakeDirEntry(BYTE type
, UBYTE
*name
, UBYTE
*entrybuffer
, globaldata
* g
)
3328 struct direntry
*direntry
;
3329 struct DateStamp time
;
3330 MUFS(struct extrafields extrafields
);
3332 entrysize
= ((sizeof(struct direntry
) + strlen(name
)) & 0xfffe);
3333 if (g
->dirextension
)
3335 direntry
= (struct direntry
*)entrybuffer
;
3336 memset(direntry
, 0, entrysize
);
3341 extrafields
.link
= 0;
3342 extrafields
.uid
= g
->user
->uid
;
3343 extrafields
.gid
= g
->user
->gid
;
3344 extrafields
.prot
= muGetDefProtection(g
->action
->dp_Port
->mp_SigTask
);
3345 direntry
->protection
= extrafields
.prot
;
3346 extrafields
.prot
&= 0xffffff00;
3351 if (!(direntry
->anode
= AllocAnode(0, g
)))
3354 direntry
->next
= entrysize
;
3355 direntry
->type
= type
;
3356 // direntry->fsize = 0;
3357 direntry
->creationday
= (UWORD
)time
.ds_Days
;
3358 direntry
->creationminute
= (UWORD
)time
.ds_Minute
;
3359 direntry
->creationtick
= (UWORD
)time
.ds_Tick
;
3360 // direntry->protection = 0x00; // RWED
3361 direntry
->nlength
= strlen(name
);
3363 // the trailing 0 of strcpy() creates the empty comment!
3364 // the flags field following this is 0 by the memset call
3365 strcpy((UBYTE
*)&direntry
->startofname
, name
);
3368 if (g
->dirextension
&& g
->muFS_ready
)
3369 AddExtraFields(direntry
, &extrafields
);
3375 /**********************************************************************/
3379 /**********************************************************************/
3382 * The loaded dirblock is locked immediately (prevents flushing)
3385 struct cdirblock
*LoadDirBlock(ULONG blocknr
, globaldata
* g
)
3387 struct cdirblock
*dirblk
;
3388 struct volumedata
*volume
= g
->currentvolume
;
3390 DB(Trace(1, "LoadDirBlock", "loading block %lx\n", blocknr
));
3391 // -I- check if already in cache
3392 if (!(dirblk
= (struct cdirblock
*)CheckCache(volume
->dirblks
, HASHM_DIR
, blocknr
, g
)))
3394 // -II- not in cache -> put it in
3395 dirblk
= (struct cdirblock
*)AllocLRU(g
);
3397 DB(Trace(10, "LoadDirBlock", "loading block %lx from disk\n", blocknr
));
3398 if (RawRead((UBYTE
*)&dirblk
->blk
, RESCLUSTER
, blocknr
, g
) == 0)
3400 if (dirblk
->blk
.id
== DBLKID
)
3402 dirblk
->volume
= g
->currentvolume
;
3403 dirblk
->blocknr
= blocknr
;
3404 dirblk
->used
= FALSE
;
3405 dirblk
->changeflag
= FALSE
;
3406 Hash(dirblk
, volume
->dirblks
, HASHM_DIR
);
3407 UpdateReference(blocknr
, dirblk
, g
); // %10
3412 args
[0] = dirblk
->blk
.id
;
3414 FreeLRU((struct cachedblock
*)dirblk
);
3415 ErrorMsg(AFS_ERROR_DNV_WRONG_DIRID
, args
, g
);
3421 FreeLRU((struct cachedblock
*)dirblk
);
3422 DB(Trace(5, "LoadDirBlock", "loading block %lx failed\n", blocknr
));
3423 // ErrorMsg(AFS_ERROR_DNV_LOAD_DIRBLOCK, NULL, g); // #$%^&??
3424 // DebugOn;DebugMsgNum("blocknr", blocknr);
3429 EXIT("LoadDirBlock");
3433 static BOOL
IsChildOf(union objectinfo child
, union objectinfo parent
, globaldata
* g
)
3436 union objectinfo up
;
3439 while (goon
&& !IsSameOI(child
, parent
))
3441 goon
= GetParent(&child
, &up
, &error
, g
);
3445 if (IsSameOI(child
, parent
))
3451 FSIZE
GetDEFileSize(struct direntry
*direntry
, globaldata
*g
)
3453 if (!LARGE_FILE_SIZE
|| !g
->largefile
)
3454 return direntry
->fsize
;
3457 struct extrafields extrafields
;
3458 GetExtraFields(direntry
, &extrafields
);
3459 return direntry
->fsize
| ((FSIZE
)extrafields
.fsizex
<< 32);
3464 ULONG
GetDEFileSize32(struct direntry
*direntry
, globaldata
*g
)
3468 if (!LARGE_FILE_SIZE
|| !g
->largefile
) {
3469 return direntry
->fsize
;
3471 size
= GetDEFileSize(direntry
, g
);
3472 if (size
> MAXFILESIZE32
)
3473 size
= MAXFILESIZE32
;
3478 void SetDEFileSize(struct direntry
*direntry
, FSIZE size
, globaldata
*g
)
3480 if (!LARGE_FILE_SIZE
|| !g
->largefile
)
3481 direntry
->fsize
= (ULONG
)size
;
3484 struct extrafields extrafields
;
3485 UWORD high
= (UWORD
)(size
>> 32);
3486 GetExtraFields(direntry
, &extrafields
);
3487 if (extrafields
.fsizex
!= high
) {
3488 extrafields
.fsizex
= high
;
3489 AddExtraFields(direntry
, &extrafields
);
3491 direntry
->fsize
= (ULONG
)size
;
3496 FSIZE
GetDDFileSize(struct deldirentry
*dde
, globaldata
*g
)
3498 if (!LARGE_FILE_SIZE
|| !g
->largefile
|| dde
->filename
[0] > DELENTRYFNSIZE
)
3502 return dde
->fsize
| ((FSIZE
)dde
->fsizex
<< 32);
3506 ULONG
GetDDFileSize32(struct deldirentry
*dde
, globaldata
*g
)
3508 FSIZE size
= GetDDFileSize(dde
, g
);
3509 if (size
> MAXFILESIZE32
)
3510 size
= MAXFILESIZE32
;
3514 void SetDDFileSize(struct deldirentry
*dde
, FSIZE size
, globaldata
*g
)
3516 dde
->fsize
= (ULONG
)size
;
3518 if (!LARGE_FILE_SIZE
|| !g
->largefile
)
3520 dde
->fsizex
= (UWORD
)(size
>> 32);
3525 * GetExtraFields (normal file only)
3527 void GetExtraFields(struct direntry
*direntry
, struct extrafields
*extrafields
)
3529 UWORD
*extra
= (UWORD
*)extrafields
;
3530 UWORD
*fields
= (UWORD
*)(((UBYTE
*)direntry
) + direntry
->next
);
3533 flags
= *(--fields
);
3534 for (i
= 0; i
< sizeof(struct extrafields
) / 2; i
++, flags
>>= 1)
3535 *(extra
++) = (flags
& 1) ? *(--fields
) : 0;
3537 /* patch protection lower 8 bits */
3538 extrafields
->prot
|= direntry
->protection
;
3543 static void GetExtraFieldsDD(struct extrafields
*extrafields
, globaldata
* g
);
3544 static void GetExtraFieldsRoot(struct extrafields
*extrafields
, globaldata
* g
);
3545 void GetExtraFieldsOI(union objectinfo
*info
, struct extrafields
*extrafields
, globaldata
* g
)
3547 if (IsVolume(*info
))
3548 GetExtraFieldsRoot(extrafields
, g
);
3549 else if (IsDelDir(*info
) || IsDelFile(*info
))
3550 GetExtraFieldsDD(extrafields
, g
);
3552 GetExtraFields(info
->file
.direntry
, extrafields
);
3555 static void GetExtraFieldsDD(struct extrafields
*extrafields
, globaldata
* g
)
3557 struct crootblockextension
*rext
= g
->currentvolume
->rblkextension
;
3559 extrafields
->link
= 0;
3560 extrafields
->uid
= rext
->blk
.dd_uid
;
3561 extrafields
->gid
= rext
->blk
.dd_gid
;
3562 extrafields
->prot
= rext
->blk
.dd_protection
;
3565 static void GetExtraFieldsRoot(struct extrafields
*extrafields
, globaldata
* g
)
3567 memset(extrafields
, 0, sizeof(struct extrafields
));
3572 void AddExtraFields(struct direntry
*direntry
, struct extrafields
*extra
)
3574 UWORD offset
, *dirext
;
3575 UWORD array
[16], i
= 0, j
= 0;
3576 UWORD flags
= 0, orvalue
;
3577 UWORD
*fields
= (UWORD
*)extra
;
3579 /* patch protection lower 8 bits */
3580 extra
->prot
&= 0xffffff00;
3581 offset
= (sizeof(struct direntry
) + (direntry
->nlength
) + *COMMENT(direntry
)) & 0xfffe;
3582 dirext
= (UWORD
*)((UBYTE
*)(direntry
) + (UBYTE
)offset
);
3585 /* fill packed field array */
3586 for (i
= 0; i
< sizeof(struct extrafields
) / 2; i
++)
3590 array
[j
++] = *fields
++;
3601 /* add fields to direntry */
3604 *dirext
++ = array
[--i
];
3607 direntry
->next
= offset
+ 2 * j
+ 2;
3612 * Updates size field of links
3614 void UpdateLinks(struct direntry
*object
, globaldata
* g
)
3616 struct canode linklist
;
3617 union objectinfo loi
;
3618 struct extrafields extrafields
;
3621 ENTER("UpdateLinks");
3622 GetExtraFields(object
, &extrafields
);
3623 linknr
= extrafields
.link
;
3626 /* Update link: get link object info and update size */
3627 GetAnode(&linklist
, linknr
, g
);
3628 FetchObject(linklist
.blocknr
, linklist
.nr
, &loi
, g
);
3629 loi
.file
.direntry
->fsize
= object
->fsize
;
3630 MakeBlockDirty((struct cachedblock
*)loi
.file
.dirblock
, g
);
3631 linknr
= linklist
.next
;
3636 * Removes link from linklist and kills direntry
3638 static BOOL
DeleteLink(struct fileinfo
*link
, SIPTR
*error
, globaldata
* g
)
3640 struct canode linknode
, linklist
;
3641 struct extrafields extrafields
;
3642 union objectinfo object
, directory
;
3643 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
3645 /* get node to remove */
3646 GetAnode(&linknode
, link
->direntry
->anode
, g
);
3647 GetExtraFields(link
->direntry
, &extrafields
);
3649 /* delete old entry */
3650 ChangeDirEntry(*link
, NULL
, NULL
, NULL
, g
);
3653 FetchObject(linknode
.clustersize
, extrafields
.link
, &object
, g
);
3654 GetExtraFields(object
.file
.direntry
, &extrafields
);
3656 /* if the object lists our link as the first link, redirect it to the next one */
3657 if (extrafields
.link
== linknode
.nr
)
3659 extrafields
.link
= linknode
.next
;
3660 memcpy(entrybuffer
, object
.file
.direntry
, object
.file
.direntry
->next
);
3661 AddExtraFields((struct direntry
*)entrybuffer
, &extrafields
);
3662 if (!GetParent(&object
, &directory
, error
, g
)) {
3663 *error
= ERROR_DISK_NOT_VALIDATED
;
3664 return DOSFALSE
; // should never happen
3667 ChangeDirEntry(object
.file
, (struct direntry
*)entrybuffer
, &directory
, &object
.file
, g
);
3670 /* otherwise simply remove the link from the list of links */
3673 GetAnode(&linklist
, extrafields
.link
, g
);
3674 while (linklist
.next
!= linknode
.nr
)
3675 GetAnode(&linklist
, linklist
.next
, g
);
3677 linklist
.next
= linknode
.next
;
3678 SaveAnode(&linklist
, linklist
.nr
, g
);
3681 FreeAnode(linknode
.nr
, g
);
3686 * Removes head of linklist and promotes first link as
3687 * master (NB: object is the main object, NOT a link).
3688 * Returns linkstate: TRUE: a link was promoted
3689 * FALSE: there was no link to promote
3691 static BOOL
RemapLinks(struct fileinfo
*object
, globaldata
* g
)
3693 struct extrafields extrafields
;
3694 struct canode linknode
;
3695 union objectinfo link
, directory
;
3696 struct direntry
*destentry
;
3697 UBYTE entrybuffer
[MAX_ENTRYSIZE
];
3700 ENTER("RemapLinks");
3701 /* get head of linklist */
3702 GetExtraFields(object
->direntry
, &extrafields
);
3703 if (extrafields
.link
== 0)
3706 /* the file has links; get head of list
3707 * we are going to promote this link to
3710 GetAnode(&linknode
, extrafields
.link
, g
);
3712 /* get direntry belonging to this linknode */
3713 FetchObject(linknode
.blocknr
, linknode
.nr
, &link
, g
);
3715 /* Promote it from link to object */
3716 destentry
= (struct direntry
*)entrybuffer
;
3717 memcpy(destentry
, link
.file
.direntry
, link
.file
.direntry
->next
);
3718 GetExtraFields(link
.file
.direntry
, &extrafields
);
3719 destentry
->type
= object
->direntry
->type
; // is this necessary?
3720 destentry
->fsize
= object
->direntry
->fsize
; // is this necessary?
3721 destentry
->anode
= object
->direntry
->anode
; // is this necessary?
3723 extrafields
.link
= linknode
.next
;
3724 AddExtraFields(destentry
, &extrafields
);
3726 /* Free old linklist node */
3727 FreeAnode(linknode
.nr
, g
);
3729 /* Remove source direntry */
3730 ChangeDirEntry(*object
, NULL
, NULL
, NULL
, g
);
3732 /* Refetch new head (can have become invalid) */
3733 FetchObject(linknode
.blocknr
, linknode
.nr
, &link
, g
);
3734 if (GetParent(&link
, &directory
, &error
, g
))
3735 ChangeDirEntry(link
.file
, destentry
, &directory
, &link
.file
, g
);
3737 /* object directory has changed; update link chain
3738 * new directory is the old chain head was in: linknode.linkdir (== linknode.blocknr)
3740 UpdateLinkDir(link
.file
.direntry
, linknode
.blocknr
, g
);
3745 * Update linklist to reflect new directory of linked to object
3747 static void UpdateLinkDir(struct direntry
*object
, ULONG newdiran
, globaldata
* g
)
3749 struct canode linklist
;
3750 struct extrafields extrafields
;
3753 ENTER("UpdateLinkDir");
3754 GetExtraFields(object
, &extrafields
);
3755 linknr
= extrafields
.link
;
3758 /* update linklist: change clustersize (== object dir) */
3759 GetAnode(&linklist
, linknr
, g
);
3760 linklist
.clustersize
= newdiran
;
3761 SaveAnode(&linklist
, linklist
.nr
, g
);
3762 linknr
= linklist
.next
;
3767 * Update linklist to reflect moved node
3768 * (is supercopy of UpdateLinkDir)
3770 static void MoveLink(struct direntry
*object
, ULONG newdiran
, globaldata
*g
)
3772 struct canode linklist
;
3773 struct extrafields extrafields
;
3777 GetExtraFields(object
, &extrafields
);
3779 /* check if is link or linked to */
3780 if (!(linknr
= extrafields
.link
))
3785 /* check filetype */
3786 if (object
->type
== ST_LINKDIR
|| object
->type
== ST_LINKFILE
)
3788 /* it is a link -> just change the linkdir */
3789 GetAnode(&linklist
, object
->anode
, g
);
3790 linklist
.blocknr
= newdiran
;
3791 SaveAnode(&linklist
, linklist
.nr
, g
);
3795 /* it is the head (linked to) */
3798 /* update linklist: change clustersize (== object dir) */
3799 GetAnode(&linklist
, linknr
, g
);
3800 linklist
.clustersize
= newdiran
; /* the object's directory */
3801 SaveAnode(&linklist
, linklist
.nr
, g
);
3802 linknr
= linklist
.next
;
3810 /**********************************************************************/
3812 /**********************************************************************/
3816 * Search an object in the del-directory and return the objectinfo if found
3818 * input : - delname: name of object to be searched for
3819 * output: - result: the searched for object
3820 * result: deldirentry * or NULL
3822 static struct deldirentry
*SearchInDeldir(STRPTR delname
, union objectinfo
*result
, globaldata
* g
)
3824 struct deldirentry
*dde
;
3825 struct cdeldirblock
*dblk
;
3827 UBYTE intl_name
[PATHSIZE
];
3828 unsigned slotnr
, offset
;
3830 ENTER("SearchInDeldir");
3831 if (!(delnumptr
= strrchr(delname
, DELENTRY_SEP
)))
3832 return FALSE
; /* no delentry seperator */
3833 stcd_i(delnumptr
+ 1, (int *) &slotnr
); /* retrieve the slotnr */
3835 *delnumptr
= 0; /* patch string to get filename part */
3836 ctodstr(delname
, intl_name
);
3838 /* truncate to maximum length */
3839 if (intl_name
[0] > FILENAMESIZE
- 1)
3840 intl_name
[0] = FILENAMESIZE
- 1;
3842 intltoupper(intl_name
); /* international uppercase objectname */
3843 *delnumptr
= DELENTRY_SEP
;
3845 /* 4.3: get deldir block */
3846 if (!(dblk
= GetDeldirBlock(slotnr
/DELENTRIES_PER_BLOCK
, g
)))
3849 offset
= slotnr
% DELENTRIES_PER_BLOCK
;
3851 dde
= &dblk
->blk
.entries
[offset
];
3852 if (intlcmp(intl_name
, dde
->filename
))
3854 if (!IsDelfileValid(dde
, dblk
, g
))
3857 result
->delfile
.special
= SPECIAL_DELFILE
;
3858 result
->delfile
.slotnr
= slotnr
;
3867 * Test if delfile is valid by scanning it's blocks
3869 static BOOL
IsDelfileValid(struct deldirentry
*dde
, struct cdeldirblock
*ddblk
, globaldata
* g
)
3871 struct canode anode
;
3873 /* check if deldirentry actually used */
3877 /* scan all blocks in the anodelist for validness */
3878 for (anode
.nr
= dde
->anodenr
; anode
.nr
; anode
.nr
= anode
.next
)
3880 GetAnode(&anode
, anode
.nr
, g
);
3881 if (BlockTaken(&anode
, g
))
3883 /* free attached anodechain */
3884 FreeAnodesInChain(dde
->anodenr
, g
); /* only FREE anodes, not blocks!! */
3886 MakeBlockDirty((struct cachedblock
*)ddblk
, g
);
3895 * Check if the blocks referenced by an anode are taken
3897 static BOOL
BlockTaken(struct canode
*anode
, globaldata
* g
)
3899 ULONG size
, bmoffset
, bmseqnr
, field
, i
, j
, blocknr
;
3900 struct cbitmapblock
*bitmap
;
3902 i
= (anode
->blocknr
- alloc_data
.bitmapstart
) / 32; // longwordnr
3903 size
= (anode
->clustersize
+ 31) / 32;
3904 bmseqnr
= i
/ alloc_data
.longsperbmb
;
3905 bmoffset
= i
% alloc_data
.longsperbmb
;
3909 /* get first bitmapblock */
3910 bitmap
= GetBitmapBlock(bmseqnr
, g
);
3912 /* check all blocks */
3913 while (bmoffset
< alloc_data
.longsperbmb
)
3915 /* check all bits in field */
3916 field
= bitmap
->blk
.bitmap
[bmoffset
];
3917 for (i
= 0, j
= 1 << 31; i
< 32; j
>>= 1, i
++)
3921 /* block is taken, check it out */
3922 blocknr
= (bmseqnr
* alloc_data
.longsperbmb
+ bmoffset
) * 32 + i
+
3923 alloc_data
.bitmapstart
;
3924 if (blocknr
>= anode
->blocknr
&& blocknr
< anode
->blocknr
+ anode
->clustersize
)
3933 /* get ready for next block */
3934 bmseqnr
= (bmseqnr
+ 1) % (alloc_data
.no_bmb
);
3942 * fill in fib. fib->fib_DiskKey must be the deldirentry number
3944 static void FillDelfileFib(struct deldirentry
*dde
, ULONG slotnr
, struct FileInfoBlock
*fib
, globaldata
*g
)
3946 struct crootblockextension
*rext
;
3953 if (!(dde
= GetDeldirEntryQuick(slotnr
, g
)))
3954 dde
= GetDeldirEntryQuick(0, g
);
3956 rext
= g
->currentvolume
->rblkextension
;
3957 size
= GetDDFileSize(dde
, g
);
3958 fib
->fib_DirEntryType
= \
3959 fib
->fib_EntryType
= ST_FILE
;
3960 fib
->fib_Protection
= rext
->blk
.dd_protection
;
3961 fib
->fib_Size
= GetDDFileSize32(dde
, g
);
3962 fib
->fib_NumBlocks
= (size
/ BLOCKSIZE
) + (size
% BLOCKSIZE
> 0);
3963 fib
->fib_Date
.ds_Days
= dde
->creationday
;
3964 fib
->fib_Date
.ds_Minute
= dde
->creationminute
;
3965 fib
->fib_Date
.ds_Tick
= dde
->creationtick
;
3966 fib
->fib_Comment
[0] = 0;
3967 fib
->fib_OwnerUID
= rext
->blk
.dd_uid
;
3968 fib
->fib_OwnerGID
= rext
->blk
.dd_gid
;
3971 nameptr
= &fib
->fib_FileName
[1];
3972 strncpy(nameptr
, &dde
->filename
[1], dde
->filename
[0]);
3973 nameptr
+= dde
->filename
[0];
3974 *nameptr
++ = DELENTRY_SEP
;
3976 /* append number appendix */
3977 fib
->fib_DiskKey
= slotnr
;
3979 for (i
= stcu_d(appbuffer
, fib
->fib_DiskKey
); i
< 3; i
++)
3981 strcpy(nameptr
, appbuffer
);
3982 fib
->fib_FileName
[0] = strlen(&fib
->fib_FileName
[1]);
3986 * Get a >valid< deldirentry starting from deldirentrynr ddnr
3987 * deldir is assumed present and enabled
3989 static struct deldirentry
*GetDeldirEntry(IPTR
*ddnr
, globaldata
* g
)
3991 struct crootblockextension
*rext
= g
->currentvolume
->rblkextension
;
3992 struct cdeldirblock
*ddblk
;
3993 struct deldirentry
*dde
;
3994 UWORD maxdelentrynr
= rext
->blk
.deldirsize
*DELENTRIES_PER_BLOCK
- 1;
3997 while (*ddnr
<= maxdelentrynr
)
3999 /* get deldirentry */
4000 if (!(ddblk
= GetDeldirBlock(*ddnr
/DELENTRIES_PER_BLOCK
, g
)))
4003 oldlock
= ddblk
->used
;
4005 dde
= &ddblk
->blk
.entries
[*ddnr
%DELENTRIES_PER_BLOCK
];
4007 /* check if dde valid */
4008 if (IsDelfileValid(dde
, ddblk
, g
))
4010 /* later --> check if blocks retaken !! */
4011 /* can be done by scanning bitmap!! */
4016 ddblk
->used
= oldlock
;
4024 * Get deldirentry deldirentrynr (NO CHECK ON VALIDITY
4025 * deldir is assumed present and enabled
4027 struct deldirentry
*GetDeldirEntryQuick(ULONG ddnr
, globaldata
*g
)
4029 struct cdeldirblock
*ddblk
;
4031 /* get deldirentry */
4032 if (!(ddblk
= GetDeldirBlock(ddnr
/DELENTRIES_PER_BLOCK
, g
)))
4035 return &ddblk
->blk
.entries
[ddnr
%DELENTRIES_PER_BLOCK
];
4038 static ULONG
FillInDDEData(struct ExAllDataEXT
*buffer
, LONG type
,
4039 struct deldirentry
*dde
, ULONG ddenr
, ULONG spaceleft
, globaldata
*g
)
4041 UWORD nameoffset
, commentoffset
= 0;
4047 /* get location to put name */
4051 size
= offsetof(struct ExAllDataEXT
, ed_Type
);
4054 size
= offsetof(struct ExAllDataEXT
, ed_Size
);
4057 size
= offsetof(struct ExAllDataEXT
, ed_Prot
);
4060 size
= offsetof(struct ExAllDataEXT
, ed_Days
);
4063 size
= offsetof(struct ExAllDataEXT
, ed_Comment
);
4066 size
= offsetof(struct ExAllDataEXT
, ed_OwnerUID
);
4069 #if EXTENDED_PACKETS_MORPHOS
4070 size
= offsetof(struct ExAllDataEXT
, ed_Size64
);
4074 size
= sizeof(struct ExAllDataEXT
);
4077 size
= offsetof(struct ExAllDataEXT
, ed_Type
);
4083 size
+= dde
->filename
[0] + 4 + 1; /* extra ddenr (3+1) and termination zero (1) */
4085 /* size of comment */
4086 if (type
>= ED_COMMENT
)
4088 commentoffset
= size
;
4093 size
= (size
+ 1) & 0xfffe;
4094 if (size
> spaceleft
)
4098 buffer
->ed_Next
= NULL
;
4101 #if EXTENDED_PACKETS_MORPHOS
4103 buffer
->ed_Size64
= GetDDFileSize(dde
, g
);
4107 buffer
->ed_OwnerUID
= g
->currentvolume
->rblkextension
->blk
.dd_uid
;
4108 buffer
->ed_OwnerGID
= g
->currentvolume
->rblkextension
->blk
.dd_gid
;
4111 buffer
->ed_Comment
= (UBYTE
*)buffer
+ commentoffset
;
4112 *((UBYTE
*)buffer
+ commentoffset
) = 0x0;
4115 buffer
->ed_Days
= dde
->creationday
;
4116 buffer
->ed_Mins
= dde
->creationminute
;
4117 buffer
->ed_Ticks
= dde
->creationtick
;
4120 buffer
->ed_Prot
= g
->currentvolume
->rblkextension
->blk
.dd_protection
;
4123 buffer
->ed_Size
= GetDDFileSize32(dde
, g
);
4126 buffer
->ed_Type
= ST_FILE
;
4130 nameptr
= (UBYTE
*)buffer
+ nameoffset
;
4131 strncpy(nameptr
, &dde
->filename
[1], dde
->filename
[0]);
4132 nameptr
+= dde
->filename
[0];
4133 *nameptr
++ = DELENTRY_SEP
;
4136 for (i
= stcu_d(appbuffer
, ddenr
); i
< 3; i
++)
4138 strcpy(nameptr
, appbuffer
);
4141 buffer
->ed_Name
= (UBYTE
*)buffer
+ nameoffset
;
4148 static struct cdeldirblock
*GetDeldirBlock(UWORD seqnr
, globaldata
*g
)
4150 struct volumedata
*volume
= g
->currentvolume
;
4151 struct crootblockextension
*rext
;
4152 struct cdeldirblock
*ddblk
;
4155 rext
= volume
->rblkextension
;
4157 if (seqnr
> MAXDELDIR
)
4159 DB(Trace(5,"GetDeldirBlock","seqnr out of range = %lx\n", seqnr
));
4160 ErrorMsg (AFS_ERROR_DELDIR_INVALID
, NULL
, g
);
4165 if (!(blocknr
= rext
->blk
.deldir
[seqnr
]))
4167 DB(Trace(5,"GetDeldirBlock","ERR: index zero\n"));
4168 ErrorMsg (AFS_ERROR_DELDIR_INVALID
, NULL
, g
);
4173 for (ddblk
= HeadOf(&volume
->deldirblks
); ddblk
->next
; ddblk
=ddblk
->next
)
4175 if (ddblk
->blk
.seqnr
== seqnr
)
4183 if (!(ddblk
= (struct cdeldirblock
*)AllocLRU(g
)))
4185 DB(Trace(5,"GetDeldirBlock","ERR: alloclru failed\n"));
4190 if (RawRead ((UBYTE
*)&ddblk
->blk
, RESCLUSTER
, blocknr
, g
) != 0)
4192 DB(Trace(5,"GetDeldirBlock","Read ERR: seqnr = %d blocknr = %lx\n", seqnr
, blocknr
));
4193 FreeLRU ((struct cachedblock
*)ddblk
);
4198 if (ddblk
->blk
.id
!= DELDIRID
)
4200 ErrorMsg (AFS_ERROR_DELDIR_INVALID
, NULL
, g
);
4201 FreeLRU ((struct cachedblock
*)ddblk
);
4202 volume
->rootblk
->options
^= MODE_DELDIR
;
4203 g
->deldirenabled
= FALSE
;
4207 ddblk
->volume
= volume
;
4208 ddblk
->blocknr
= blocknr
;
4209 ddblk
->used
= FALSE
;
4210 ddblk
->changeflag
= FALSE
;
4212 /* add to cache and return */
4213 MinAddHead (&volume
->deldirblks
, ddblk
);
4217 struct cdeldirblock
*NewDeldirBlock(UWORD seqnr
, globaldata
*g
)
4219 struct volumedata
*volume
= g
->currentvolume
;
4220 struct crootblockextension
*rext
;
4221 struct cdeldirblock
*ddblk
;
4224 rext
= volume
->rblkextension
;
4226 if (seqnr
> MAXDELDIR
)
4228 DB(Trace(5, "NewDelDirBlock", "seqnr out of range = %lx\n", seqnr
));
4232 /* alloc block and LRU slot */
4233 if (!(ddblk
= (struct cdeldirblock
*)AllocLRU(g
)) ||
4234 !(blocknr
= AllocReservedBlock(g
)) )
4237 FreeLRU((struct cachedblock
*)ddblk
);
4241 /* make reference */
4242 rext
->blk
.deldir
[seqnr
] = blocknr
;
4245 ddblk
->volume
= volume
;
4246 ddblk
->blocknr
= blocknr
;
4247 ddblk
->used
= FALSE
;
4248 ddblk
->blk
.id
= DELDIRID
;
4249 ddblk
->blk
.seqnr
= seqnr
;
4250 ddblk
->changeflag
= TRUE
;
4251 ddblk
->blk
.protection
= DELENTRY_PROT
; /* re..re..re.. */
4252 ddblk
->blk
.creationday
= volume
->rootblk
->creationday
;
4253 ddblk
->blk
.creationminute
= volume
->rootblk
->creationminute
;
4254 ddblk
->blk
.creationtick
= volume
->rootblk
->creationtick
;
4256 /* add to cache and return */
4257 MinAddHead(&volume
->deldirblks
, ddblk
);
4261 /* Allocate deldirslot. Free anodechain attached to slot and clear it.
4262 * An intermediate update is possible, due to FreeAnodesInChain()
4264 static int AllocDeldirSlot(globaldata
* g
)
4266 struct crootblockextension
*rext
= g
->currentvolume
->rblkextension
;
4267 struct cdeldirblock
*ddblk
;
4268 struct deldirentry
*dde
;
4272 /* get deldirentry and update roving ptr */
4273 ddnr
= rext
->blk
.deldirroving
;
4274 if (!(ddblk
= GetDeldirBlock(ddnr
/DELENTRIES_PER_BLOCK
,g
)))
4276 rext
->blk
.deldirroving
= 0;
4280 dde
= &ddblk
->blk
.entries
[ddnr
%DELENTRIES_PER_BLOCK
];
4281 rext
->blk
.deldirroving
= (rext
->blk
.deldirroving
+ 1) %
4282 (rext
->blk
.deldirsize
*DELENTRIES_PER_BLOCK
);
4283 MakeBlockDirty((struct cachedblock
*)ddblk
, g
);
4285 anodenr
= dde
->anodenr
;
4288 /* clear it for reuse */
4291 /* free attached anodechain */
4292 FreeAnodesInChain(anodenr
, g
); /* only FREE anodes, not blocks!! */
4295 DB(Trace(1, "AllocDelDirSlot", "Allocate slot %ld\n", ddnr
));
4300 /* Add a file to the deldir.
4301 * Deldir assumed enabled here, and info assumed a file (ST_FILE)
4302 * ddnr is deldir slot to use. Slot is assumed to be allocated by
4305 static void AddToDeldir(union objectinfo
*info
, int ddnr
, globaldata
* g
)
4307 struct cdeldirblock
*ddblk
;
4308 struct deldirentry
*dde
;
4309 struct direntry
*de
= info
->file
.direntry
;
4310 struct crootblockextension
*rext
;
4311 struct DateStamp time
;
4313 DB(Trace(1, "AddToDeldir", "slotnr %ld\n", ddnr
));
4314 /* get deldirentry to put it in */
4315 ddblk
= GetDeldirBlock(ddnr
/DELENTRIES_PER_BLOCK
, g
);
4316 dde
= &ddblk
->blk
.entries
[ddnr
%DELENTRIES_PER_BLOCK
];
4318 /* put new one in */
4319 dde
->anodenr
= de
->anode
;
4320 SetDDFileSize(dde
, GetDEFileSize(de
, g
), g
);
4321 dde
->creationday
= de
->creationday
;
4322 dde
->creationminute
= de
->creationminute
;
4323 dde
->creationtick
= de
->creationtick
;
4324 dde
->filename
[0] = min(DELENTRYFNSIZE
- 1, de
->nlength
);
4325 strncpy(&dde
->filename
[1], &de
->startofname
, dde
->filename
[0]);
4327 /* Touch deldir block. Inserted here, simply because this the only
4328 * place touching the deldir will be needed.
4329 * Note: Only this copy is touched ...
4332 rext
= g
->currentvolume
->rblkextension
;
4333 ddblk
->blk
.creationday
= rext
->blk
.dd_creationday
= (UWORD
)time
.ds_Days
;
4334 ddblk
->blk
.creationminute
= rext
->blk
.dd_creationminute
= (UWORD
)time
.ds_Minute
;
4335 ddblk
->blk
.creationtick
= rext
->blk
.dd_creationtick
= (UWORD
)time
.ds_Tick
;
4338 MakeBlockDirty((struct cachedblock
*)ddblk
, g
);
4341 /* Set number of deldir blocks (Has to be single threaded)
4342 * If 0 then deldir is disabled (but MODE_DELDIR stays;
4343 * InitModules() detect that the number of deldirblocks is 0)
4344 * There must be a currentvolume
4345 * Returns error (0 = success)
4347 ULONG
SetDeldir(int nbr
, globaldata
*g
)
4349 struct crootblockextension
*rext
= g
->currentvolume
->rblkextension
;
4350 struct cdeldirblock
*ddblk
, *next
;
4356 if (nbr
< 0 || nbr
> MAXDELDIR
+1)
4357 return ERROR_BAD_NUMBER
;
4359 /* check if there are locks on any deldir, delfile */
4360 for (list
= HeadOf(&g
->currentvolume
->fileentries
); list
->next
; list
=list
->next
)
4362 if (IsDelDir(list
->info
) || IsDelFile(list
->info
))
4363 return ERROR_OBJECT_IN_USE
;
4369 for (ddblk
= HeadOf(&g
->currentvolume
->deldirblks
); (next
=ddblk
->next
); ddblk
=next
)
4371 FlushBlock((struct cachedblock
*)ddblk
, g
);
4372 MinRemove(LRU_CHAIN(ddblk
));
4373 MinAddHead(&g
->glob_lrudata
.LRUpool
, LRU_CHAIN(ddblk
));
4374 // i.p.v. FreeLRU((struct cachedblock *)ddblk, g);
4377 /* free unwanted deldir blocks */
4378 for (i
= nbr
; i
< rext
->blk
.deldirsize
; i
++)
4380 FreeReservedBlock(rext
->blk
.deldir
[i
], g
);
4381 rext
->blk
.deldir
[i
] = 0;
4384 /* allocate wanted ones */
4385 for (i
= rext
->blk
.deldirsize
; i
< nbr
; i
++)
4387 if (!NewDeldirBlock(i
,g
))
4390 error
= ERROR_DISK_FULL
;
4395 /* if deldir size increases, start roving in a the new area
4396 * if deldir size decreases, start roving from the start
4398 if (nbr
> rext
->blk
.deldirsize
)
4399 rext
->blk
.deldirroving
= rext
->blk
.deldirsize
* DELENTRIES_PER_BLOCK
;
4401 rext
->blk
.deldirroving
= 0;
4403 /* enable/disable */
4404 rext
->blk
.deldirsize
= nbr
;
4405 g
->deldirenabled
= (nbr
> 0);
4407 MakeBlockDirty((struct cachedblock
*)rext
, g
);