Added a test for MUIA_Listview_SelectChange.
[AROS.git] / rom / filesys / pfs3 / fs / dd_funcs.c
blob089c4b9420f0a4163100b64812e288aa369d3f2f
1 /* $Id$ */
2 /* $Log: dd_funcs.c $
3 * Revision 1.20 1999/09/11 17:05:14 Michiel
4 * bugfix version 18.4
6 * Revision 1.19 1999/05/14 11:31:34 Michiel
7 * Long filename support implemented; bugfixes
9 * Revision 1.18 1999/03/25 22:03:12 Michiel
10 * Allow setdeldir for muROOT_UID only
11 * Check volume for setdeldir
12 * Added deldir inquiry option
14 * Revision 1.17 1999/02/22 16:27:21 Michiel
15 * dd_SetDeldir added
17 * Revision 1.16 1998/09/27 11:26:37 Michiel
18 * Error incurred softlock can now be disabled in dd_WriteProtect
20 * Revision 1.15 1998/05/31 16:27:42 Michiel
21 * added ACTION_IS_PFS2
23 * Revision 1.14 1998/05/29 19:31:18 Michiel
24 * fixed bug 107
26 * Revision 1.13 1998/05/27 20:16:13 Michiel
27 * AFS --> PFS2
28 * Allow ID_PFS2_DISK in custom packets
30 * Revision 1.12 1997/03/03 22:04:04 Michiel
31 * Release 16.21
33 * Revision 1.11 1996/03/14 19:29:43 Michiel
34 * using new NewFile specification
36 * Revision 1.10 1996/03/07 10:06:34 Michiel
37 * DICE MakeIndex fix (wt)
38 * Rename MuAF access (wt)
40 * Revision 1.9 1996/01/30 12:48:52 Michiel
41 * --- working tree overlap ---
42 * new notify routines
44 * Revision 1.8 1995/12/29 11:03:17 Michiel
45 * dd_SetRollover added
47 * Revision 1.7 1995/12/20 11:28:10 Michiel
48 * indented
50 * Revision 1.6 1995/12/07 15:25:38 Michiel
51 * rollover support and bugfixes
53 * Revision 1.5 1995/11/07 14:52:34 Michiel
54 * FreeUnusedResources after flush
56 * Revision 1.4 1995/09/01 11:14:40 Michiel
57 * fixed enforcer hit in dd_Open
58 * */
61 /**********************
62 * function prototypes
65 static SIPTR NotKnown(struct DosPacket *pkt, globaldata * g);
66 static SIPTR NotYetImplemented(struct DosPacket *pkt, globaldata * g);
67 static SIPTR dd_IsFileSystem(struct DosPacket *pkt, globaldata * g);
68 static SIPTR dd_Quit(struct DosPacket *pkt, globaldata * g);
69 static SIPTR dd_CurrentVolume(struct DosPacket *pkt, globaldata * g);
70 static SIPTR dd_Lock(struct DosPacket *pkt, globaldata * g);
71 static SIPTR dd_Unlock(struct DosPacket *pkt, globaldata * g);
72 static SIPTR dd_DupLock(struct DosPacket *pkt, globaldata * g);
73 static SIPTR dd_CreateDir(struct DosPacket *pkt, globaldata * g);
74 static SIPTR dd_Parent(struct DosPacket *pkt, globaldata * g);
75 static SIPTR dd_SameLock(struct DosPacket *pkt, globaldata * g);
76 static SIPTR dd_Open(struct DosPacket *pkt, globaldata * g);
77 static SIPTR dd_OpenFromLock(struct DosPacket *pkt, globaldata * g);
78 static SIPTR dd_Close(struct DosPacket *pkt, globaldata * g);
79 static SIPTR dd_ChangeMode(struct DosPacket *pkt, globaldata * g);
80 static SIPTR dd_SeekRead(struct DosPacket *pkt, globaldata * g);
81 static SIPTR dd_WriteSFS(struct DosPacket *pkt, globaldata * g);
82 static SIPTR dd_Relabel(struct DosPacket *pkt, globaldata * g);
83 static SIPTR dd_AddBuffers(struct DosPacket *pkt, globaldata * g);
84 static SIPTR dd_Info(struct DosPacket *pkt, globaldata * g);
85 static SIPTR dd_Flush(struct DosPacket *pkt, globaldata * g);
86 static SIPTR dd_WriteProtect(struct DosPacket *pkt, globaldata * g);
87 static SIPTR dd_SerializeDisk(struct DosPacket *pkt, globaldata * g);
88 static SIPTR dd_DeleteObject(struct DosPacket *pkt, globaldata * g);
89 static SIPTR dd_Rename(struct DosPacket *pkt, globaldata * g);
90 static SIPTR dd_SetProperty(struct DosPacket *pkt, globaldata * g);
91 static SIPTR dd_Examine(struct DosPacket *pkt, globaldata * g);
92 static SIPTR dd_ExamineAll(struct DosPacket *pkt, globaldata * g);
93 static SIPTR dd_MakeLink(struct DosPacket *pkt, globaldata * g);
94 static SIPTR dd_ReadLink(struct DosPacket *pkt, globaldata * g);
95 static SIPTR dd_InhibitOn(struct DosPacket *pkt, globaldata * g);
96 static SIPTR dd_InhibitOff(struct DosPacket *pkt, globaldata * g);
97 static SIPTR dd_Format(struct DosPacket *pkt, globaldata * g);
98 static SIPTR dd_AddNotify(struct DosPacket *pkt, globaldata * g);
99 static SIPTR dd_RemoveNotify(struct DosPacket *pkt, globaldata * g);
100 static SIPTR dd_SignalIdle(struct DosPacket *pkt, globaldata * g);
102 /* internal packets; PFS2 extensions */
103 static int dd_CheckCustomPacket(LONG id);
104 static SIPTR dd_IsPFS2 (struct DosPacket *pkt, globaldata *g);
105 static SIPTR dd_KillEmpty(struct DosPacket *pkt, globaldata * g);
106 static SIPTR dd_RemoveDirEntry(struct DosPacket *pkt, globaldata * g);
108 #if EXTRAPACKETS
109 static SIPTR dd_Sleep(struct DosPacket *pkt, globaldata * g);
110 static SIPTR dd_UpdateAnode(struct DosPacket *pkt, globaldata * g);
111 static SIPTR dd_SetFileSize(struct DosPacket *pkt, globaldata *g);
112 #if ROLLOVER
113 static SIPTR dd_MakeRollover(struct DosPacket *pkt, globaldata * g);
114 static SIPTR dd_SetRollover(struct DosPacket *pkt, globaldata *g);
115 #endif /* ROLLOVER */
116 #if DELDIR
117 static SIPTR dd_SetDeldir(struct DosPacket *pkt, globaldata *g);
118 #endif
119 #endif /* ExtraPackets */
120 #if defined(__MORPHOS__)
121 static LONG dd_MorphOSQueryAttr(struct DosPacket *pkt, globaldata *g);
122 #endif
125 /**********************
126 * table functions
129 static SIPTR NotKnown(struct DosPacket *pkt, globaldata * g)
131 pkt->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
132 return DOSFALSE;
135 static SIPTR NotYetImplemented(struct DosPacket *pkt, globaldata * g)
137 pkt->dp_Res2 = ERROR_NOT_IMPLEMENTED;
138 return DOSFALSE;
141 static SIPTR dd_IsFileSystem(struct DosPacket *pkt, globaldata * g)
143 return DOSTRUE;
146 /* causes PFS2 to quit. The dieing-flag will cause main to call
147 * Quit() after returning the packet
149 static SIPTR dd_Quit(struct DosPacket *pkt, globaldata * g)
151 #if UNSAFEQUIT
152 g->dieing = TRUE;
153 return DOSTRUE;
154 #else
155 struct volumedata *volume = g->currentvolume;
157 if (!volume || (IsMinListEmpty(&volume->fileentries) && IsMinListEmpty(&volume->notifylist)))
159 g->dieing = TRUE;
160 return DOSTRUE;
162 else
164 pkt->dp_Res2 = ERROR_OBJECT_IN_USE;
165 return DOSFALSE;
167 #endif
170 static SIPTR dd_CurrentVolume(struct DosPacket *pkt, globaldata * g)
172 /* arguments fixed 18-04-94 */
173 // ARG1 = APTR fileentry. (filled in by Open()) of NULL
174 // RES1 = BPTR to volume node structure
175 // RES2 = Unit number
177 pkt->dp_Res2 = g->startup->fssm_Unit;
179 if (!pkt->dp_Arg1)
181 if (g->currentvolume)
182 return (SIPTR)MKBADDR(g->currentvolume->devlist);
183 else
184 return (SIPTR)BNULL;
186 else
187 return (SIPTR)MKBADDR(((fileentry_t *) pkt->dp_Arg1)->le.volume->devlist);
191 /**********************
192 * Lock functions
195 static SIPTR dd_Lock(struct DosPacket *pkt, globaldata * g)
197 // ARG1 = Lock on directory ARG2 is relative to (BPTR)
198 // ARG2 = BSTR Name of object
199 // ARG3 = LONG mode: SHARED_LOCK, EXCLUSIVE_LOCK
200 // RES1 = Lock on requested object (0=failure)
201 // RES2 = failurecode
203 lockentry_t *parentfe;
204 listentry_t *filefe;
205 union objectinfo filefi, *parentfi;
206 UBYTE pathname[PATHSIZE], *fullname;
207 listtype type;
208 SIPTR *error = &pkt->dp_Res2;
209 #if MULTIUSER
210 struct extrafields extrafields;
211 ULONG flags;
212 #endif
214 ENTER("Lock");
216 GetFileInfoFromLock(pkt->dp_Arg1, 0, parentfe, parentfi);
217 BCPLtoCString(pathname, (DSTR)BARG2(pkt));
218 DB(Trace(1, "Lock", "locking : %s parent: %lx \n", pathname, pkt->dp_Arg1));
219 DB(if (parentfi) Trace(1, "Lock", "anodenr = %lx and %lx \n", parentfe->nextanode,
220 (parentfi->file.direntry ? parentfi->file.direntry->anode : ANODE_ROOTDIR)));
221 SkipColon(fullname, pathname);
223 /* Locate object
224 * .. if no filename then lock parent
226 if (parentfi && !*fullname)
227 filefi = *parentfi;
228 else if (!FindObject(parentfi, fullname, &filefi, error, g))
230 DB(Trace(1, "Lock", "failed at locktime : %s\n", fullname));
231 return 0L;
234 // Add object to list
235 if (IsVolume(filefi))
237 type.value = ET_VOLUME + ET_SHAREDREAD;
239 else
241 type.value = ET_LOCK;
242 type.flags.access = (pkt->dp_Arg3 == EXCLUSIVE_LOCK ? ET_EXCLREAD : ET_SHAREDREAD);
244 #if MULTIUSER
245 #if DELDIR
246 GetExtraFieldsOI(&filefi, &extrafields, g);
247 #else /* DELDIR */
248 GetExtraFields(filefi.file.direntry, &extrafields);
249 #endif /* DELDIR */
251 flags = muGetRelationship(extrafields);
253 if (!(flags & muRel_PROPERTY_ACCESS) &&
254 (*error = muFS_CheckReadAccess(extrafields.prot, flags, g)))
255 return 0;
256 #endif /* MULTIUSER */
259 if (!(filefe = MakeListEntry(&filefi, type, error, g)))
260 return 0;
262 if (!AddListEntry(filefe))
264 DB(Trace(1, "dd_Lock", "object in use"));
266 FreeListEntry(filefe, g);
267 *error = ERROR_OBJECT_IN_USE;
268 return 0;
271 DB(Trace(1, "Lock", "adres: %lx\n", filefe));
272 pkt->dp_Res2 = 0;
273 return (SIPTR)MKBADDR(&filefe->lock);
276 static SIPTR dd_Unlock(struct DosPacket *pkt, globaldata * g)
278 // ARG1 = LOCK to free
279 // RES1 = BOOL TRUE
281 listentry_t *listentry;
283 listentry = ListEntryFromLock(pkt->dp_Arg1);
284 if (listentry)
286 // not needed: UpdateLE(listentry, g);
287 RemoveListEntry(listentry, g);
290 return DOSTRUE;
293 static SIPTR dd_DupLock(struct DosPacket *pkt, globaldata * g)
295 // ARG1 = BPTR lock to duplicate / filehandle->fh_Arg1 to dup
296 // RES1 = Duplicated lock
297 // RES2 = failure code if RES1=0
299 // scrfe: oorspronkelijke fileentry
300 // dstfe: copy van scrfe
302 lockentry_t *srcfe, *dstfe;
303 union objectinfo filefi;
304 listtype type;
306 if (!pkt->dp_Arg1)
308 if (!g->currentvolume)
310 pkt->dp_Res2 = ERROR_NO_DISK;
311 return 0;
314 /* return lock to root (GURU 605) */
315 filefi.volume.root = 0;
316 filefi.volume.volume = g->currentvolume;
317 type.value = ET_VOLUME + ET_SHAREDREAD;
318 if (!(dstfe = (lockentry_t *)MakeListEntry(&filefi, type, &pkt->dp_Res2, g)))
319 return 0;
321 goto dl_add;
324 /* get entry struct */
325 if (pkt->dp_Type == ACTION_COPY_DIR)
326 srcfe = LockEntryFromLock(pkt->dp_Arg1);
327 else
328 srcfe = (lockentry_t *)pkt->dp_Arg1;
330 if (!CheckVolume(srcfe->le.volume, 0, &pkt->dp_Res2, g))
331 return DOSFALSE;
332 UpdateLE((listentry_t *)srcfe, g);
334 /* only allow SHAREDREAD locks & fe's */
335 if (srcfe->le.type.flags.access != ET_SHAREDREAD)
337 pkt->dp_Res2 = ERROR_OBJECT_IN_USE;
338 return 0;
341 if (!(dstfe = (lockentry_t *) AllocMemP(sizeof(lockentry_t), g)))
343 pkt->dp_Res2 = ERROR_NO_FREE_STORE;
344 return 0;
347 /* only copy the listentry_t part. The extension fields (nextanode,
348 * nextentry and nextdirblock are all zero
350 CopyMem(srcfe, dstfe, sizeof(listentry_t));
352 /* if COPY_DIR_FH then update type to LOCK */
353 if (pkt->dp_Type == ACTION_COPY_DIR_FH)
354 dstfe->le.type.flags.type = ETF_LOCK;
356 dl_add:
357 if (!AddListEntry((listentry_t *)dstfe))
359 FreeListEntry((listentry_t *)dstfe, g); // Niet mogelijk SHAREDREAD always copyable
361 pkt->dp_Res2 = ERROR_OBJECT_IN_USE;
362 return 0;
365 DB(Trace(1, "DupLock", "of %lx adres: %lx\n", srcfe, dstfe));
366 return (SIPTR)MKBADDR(&dstfe->le.lock);
369 static SIPTR dd_CreateDir(struct DosPacket *pkt, globaldata * g)
371 // ARG1 = Lock on directory ARG2 is relative to (BPTR)
372 // ARG2 = BSTR Name of new directory
373 // RES1 = Lock on new directory
374 // RES2 = failurecode (if res1 = DOSFALSE)
376 lockentry_t *parentle, *newdirle;
377 union objectinfo path, *parentfi;
378 UBYTE *dirname, pathname[PATHSIZE];
379 UBYTE *zonderpad;
380 SIPTR *error = &pkt->dp_Res2;
381 #if MULTIUSER
382 #if MU_CHECKDIR
383 struct extrafields extrafields;
384 ULONG flags;
385 #endif
386 #endif
388 GetFileInfoFromLock(pkt->dp_Arg1, 1, parentle, parentfi);
389 BCPLtoCString(pathname, (DSTR)BARG2(pkt));
390 SkipColon(dirname, pathname);
391 zonderpad = GetFullPath(parentfi, dirname, &path, error, g);
392 if (!zonderpad)
393 return DOSFALSE;
395 #if MULTIUSER
396 #if MU_CHECKDIR
397 if (!IsVolume(path))
399 #if DELDIR
400 GetExtraFieldsOI(&path, &extrafields);
401 #else /* DELDIR */
402 GetExtraFields(path.file.direntry, &extrafields);
403 #endif /* DELDIR */
404 flags = muGetRelationship(extrafields);
405 if (*error = muFS_CheckWriteAccess(extrafields.prot, flags, g))
406 return DOSFALSE;
408 #endif /* MU_CHECKDIR */
409 #endif /* MULTIUSER */
411 newdirle = NewDir(&path, zonderpad, error, g);
413 if (newdirle)
415 PFSDoNotify(&newdirle->le.info.file, TRUE, g);
416 return (SIPTR)MKBADDR(&newdirle->le.lock);
418 else
419 return DOSFALSE;
422 static SIPTR dd_Parent(struct DosPacket *pkt, globaldata * g)
424 // ACTION_PARENT en ACTION_PARENT_FH
425 // ARG1 = BPTR Lock on object to get the parent of
426 // ARG1.FH = filehandle->dp_Arg1 == &listentry
427 // RES1 = BPTR Parent lock
428 // RES2 = failure code (if res1 = 0)
430 lockentry_t *childfe;
431 listentry_t *parentfe;
432 listtype type;
433 union objectinfo *childfi, parentfi;
434 SIPTR *error = &pkt->dp_Res2;
436 // get fe & fi of child
437 if (pkt->dp_Type == ACTION_PARENT)
438 childfe = LockEntryFromLock(pkt->dp_Arg1);
439 else
440 childfe = (lockentry_t *) (pkt->dp_Arg1);
442 /* check if volume present and update lock */
443 if (childfe)
445 if (!CheckVolume(childfe->le.volume, 0, error, g))
446 return DOSFALSE;
447 UpdateLE((listentry_t *)childfe, g);
448 childfi = &childfe->le.info;
450 else
452 if (!g->currentvolume)
454 *error = ERROR_NO_DISK;
455 return 0;
457 childfi = NULL;
460 // get fi of parent
461 if (!GetParent(childfi, &parentfi, &pkt->dp_Res2, g))
462 return 0;
464 // make and enter a fileentry
465 type.value = 0;
466 type.flags.type = IsVolume(parentfi) ? (ETF_VOLUME) : (ETF_LOCK);
467 type.flags.access = ET_SHAREDREAD;
469 if (!(parentfe = MakeListEntry(&parentfi, type, &pkt->dp_Res2, g)))
470 return 0;
472 if (!AddListEntry(parentfe))
474 FreeListEntry(parentfe, g);
475 pkt->dp_Res2 = ERROR_OBJECT_IN_USE;
476 //NormalErrorMsg("ßE Parent failed", NULL);
477 return (0);
480 return (SIPTR)MKBADDR(&parentfe->lock);
484 /* Somehow a filehandler should send opposite values: */
485 #define H_LOCK_SAME 1
486 #define H_LOCK_SAME_VOLUME 0
488 static SIPTR dd_SameLock(struct DosPacket *pkt, globaldata * g)
490 // ARG1 = BPTR Lock 1 to compare
491 // ARG2 = BPTR Lock 2 to compare
492 // RES1 = LONG result of compare
493 // RES2 = CODE failurecode (if res1 = LOCK_DIFFERENT)
495 lockentry_t *lock1, *lock2;
497 lock1 = LockEntryFromLock(pkt->dp_Arg1);
498 UpdateLE((listentry_t *)lock1, g);
499 lock2 = LockEntryFromLock(pkt->dp_Arg2);
500 UpdateLE((listentry_t *)lock2, g);
501 pkt->dp_Res2 = 0;
503 if (!lock1 || !lock2)
505 pkt->dp_Res2 = ERROR_INVALID_LOCK;
506 return LOCK_DIFFERENT;
509 if (lock1->le.volume != lock2->le.volume)
510 return LOCK_DIFFERENT;
512 if (lock1->le.anodenr == lock2->le.anodenr)
513 return H_LOCK_SAME;
514 else
515 return H_LOCK_SAME_VOLUME;
519 /**********************
520 * Filehandle functions
523 static SIPTR dd_Open(struct DosPacket *pkt, globaldata * g)
525 // ARG1 = BPTR Filehandle to fill in
526 // ARG2 = BPTR LOCK on directory ARG3 is relative to
527 // ARG3 = BSTR Name of file to be opened
528 // RES1 = Success/Failure (DOSTRUE/DOSFALSE)
529 // RES2 = failure code
531 // fullname: name inclusief pat
532 // filename: filename zonder pat
533 // pathfi: fileinfo van path van te openen file
534 // filefi: fileinfo van te openen file
535 // mode: nodetype van fileentry van file
537 // GURUbook: ACTION_FINDINPUT premits write access (598)
539 struct FileHandle *filehandle;
540 listentry_t *filefe;
541 lockentry_t *parentfe;
542 union objectinfo pathfi, filefi, *parentfi;
543 listtype type;
544 SIPTR *error = &pkt->dp_Res2;
545 UBYTE pathname[PATHSIZE], *fullname, *filename = NULL;
546 BOOL found;
547 #if MULTIUSER
548 struct extrafields extrafields;
549 ULONG flags;
550 #if MU_CHECKDIR
551 struct extrafields path_extrafields;
552 ULONG path_flags;
553 #endif /* MU_CHECKDIR */
554 #endif /* MULTIUSER */
556 // -I- benodigde waarden afleiden van pakket
557 filehandle = (struct FileHandle *)BADDR(pkt->dp_Arg1);
558 GetFileInfoFromLock(pkt->dp_Arg2, 0, parentfe, parentfi);
559 BCPLtoCString(pathname, (DSTR)BARG3(pkt));
560 DB(Trace(1, "Open", "%s\n", pathname));
561 SkipColon(fullname, pathname);
563 /* 15.9: check if path is file. If so it has to be opened
564 * if an empty string was specified as filename
565 * (see GuruBook:599)
567 if (parentfi && IsFile(*parentfi) && *fullname == 0)
569 found = TRUE;
570 filefi = *parentfi;
572 else
574 /* Get path to file */
575 if (!(filename = GetFullPath(parentfi, fullname, &pathfi, error, g)))
576 return DOSFALSE;
578 /* try to locate file */
579 found = FindObject(&pathfi, filename, &filefi, error, g);
582 if (found)
584 /* softlinks cannot directly be opened */
585 if (IsSoftLink(filefi))
587 *error = ERROR_IS_SOFT_LINK;
588 return DOSFALSE;
591 /* check if file (only files can be opened) */
592 #if DELDIR
593 if ((IsVolume(filefi) || IsDelDir(filefi) || IsDir(filefi)))
594 #else
595 if ((IsVolume(filefi) || IsDir(filefi)))
596 #endif
598 *error = ERROR_OBJECT_WRONG_TYPE;
599 return DOSFALSE;
603 type.value = ET_FILEENTRY;
605 #if MULTIUSER
606 #if MU_CHECKDIR
607 if (IsVolume(pathfi))
608 memset(&path_extrafields, 0, sizeof(struct extrafields));
609 else
610 #if DELDIR
611 GetExtraFieldsOI(&pathfi, &path_extrafields);
612 #else /* DELDIR */
613 GetExtraFields(pathfi.file.direntry, &path_extrafields);
614 #endif /* DELDIR */
615 #endif /* MU_CHECKDIR */
617 if (found)
618 #if DELDIR
619 GetExtraFieldsOI(&filefi, &extrafields, g);
620 #else
621 GetExtraFields(filefi.file.direntry, &extrafields);
622 #endif
624 if (g->muFS_ready)
626 #if MU_CHECKDIR
627 path_flags = muGetRelationshipA(g->user, (path_extrafields.uid << 16) + path_extrafields.gid, NULL);
628 #endif
629 if (found)
630 flags = muGetRelationshipA(g->user, (extrafields.uid << 16) + extrafields.gid, NULL);
632 else
634 #if MU_CHECKDIR
635 path_flags = ((path_extrafields.uid == muNOBODY_UID) << muRelB_NO_OWNER) | muRelF_NOBODY;
636 #endif
637 if (found)
638 flags = ((extrafields.uid == muNOBODY_UID) << muRelB_NO_OWNER) | muRelF_NOBODY;
640 #endif /* MULTIUSER */
642 switch (pkt->dp_Type)
644 case ACTION_FINDINPUT:
645 if (!found)
646 return DOSFALSE;
648 #if MULTIUSER
649 if ((*error = muFS_CheckReadAccess(extrafields.prot, flags, g)))
650 return DOSFALSE;
651 #endif
652 type.flags.access = ET_SHAREDREAD;
653 break;
655 case ACTION_FINDUPDATE:
657 #if MULTIUSER
658 if (found)
660 if ((*error = muFS_CheckWriteAccess(extrafields.prot, flags, g)))
661 return DOSFALSE;
663 #if MU_CHECKDIR
664 else
666 if ((*error = muFS_CheckWriteAccess(path_extrafields.prot, path_flags, g)))
667 return DOSFALSE;
669 #endif /* MU_CHECKDIR */
670 #endif /* MULTIUSER */
672 if (!found)
674 if ((*error = NewFile (found, &pathfi, filename, &filefi, g)))
676 DB(Trace(1, "NewFile", "update failed"));
677 return DOSFALSE;
681 type.flags.access = ET_SHAREDWRITE;
682 break;
684 case ACTION_FINDOUTPUT:
685 if (found)
687 #if MULTIUSER
688 if ((*error = muFS_CheckDeleteAccess(extrafields.prot, flags, g)))
689 return DOSFALSE;
691 if ((*error = muFS_CheckWriteAccess(extrafields.prot, flags, g)))
692 return DOSFALSE;
695 #if MU_CHECKDIR
696 if ((*error = muFS_CheckWriteAccess(path_extrafields.prot, path_flags, g)))
697 return DOSFALSE;
698 #endif /* MU_CHECKDIR */
699 #else /* MULTIUSER */
701 #endif /* MULTIUSER */
703 if ((*error = NewFile (found, &pathfi, filename, &filefi, g)))
705 DB(Trace(1, "Newfile", "output failed"));
706 return DOSFALSE;
709 type.flags.access = ET_EXCLWRITE;
710 break;
712 default:
713 *error = ERROR_ACTION_NOT_KNOWN;
714 return DOSFALSE;
717 /* Add file to list */
718 if (!(filefe = MakeListEntry(&filefi, type, error, g)))
719 return DOSFALSE;
721 if (!AddListEntry(filefe))
723 DB(Trace(1, "dd_Open", "AddListEntry failed"));
724 FreeListEntry(filefe, g);
725 *error = ERROR_OBJECT_IN_USE;
726 return DOSFALSE;
729 /* if the file was created, the user has to be notified */
730 ((fileentry_t *) filefe)->checknotify = !found;
731 filehandle->fh_Arg1 = (SIPTR)filefe; // We get this with Read(), Write() etc
733 return DOSTRUE;
736 static SIPTR dd_OpenFromLock(struct DosPacket *pkt, globaldata * g)
738 // ARG1 = BPTR to filehandle
739 // ARG2 = BPTR lock on file to open
740 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
741 // RES2 = failurecode (if res1 = DOSFALSE)
743 struct FileHandle *filehandle;
744 listentry_t *lockentry, *fileentry;
745 listtype type;
747 filehandle = (struct FileHandle *)BADDR(pkt->dp_Arg1);
748 if (!(lockentry = ListEntryFromLock(pkt->dp_Arg2)) ||
749 !CheckVolume(lockentry->volume, 0, &pkt->dp_Res2, g))
750 return DOSFALSE;
752 UpdateLE(lockentry, g);
753 if (!IsFile(lockentry->info))
755 pkt->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
756 return DOSFALSE;
759 type.value = (lockentry->lock.fl_Access == EXCLUSIVE_LOCK) ? \
760 (ET_FILEENTRY | ET_EXCLWRITE) : (ET_FILEENTRY | ET_SHAREDREAD);
761 if (!(fileentry = MakeListEntry(&lockentry->info, type, &pkt->dp_Res2, g)))
762 return DOSFALSE;
764 /* oude lock verwijderen; nieuwe fileentry toevoegen
765 * addlistentry zou eigenlijk niet fout moeten kunnen gaan
767 RemoveListEntry(lockentry, g);
768 if (!AddListEntry(fileentry)) /* should not go wrong */
770 FreeListEntry(fileentry, g);
771 pkt->dp_Res2 = ERROR_OBJECT_IN_USE;
772 return DOSFALSE;
775 filehandle->fh_Arg1 = (SIPTR)fileentry;
776 return DOSTRUE;
779 static SIPTR dd_Close(struct DosPacket *pkt, globaldata * g)
781 SIPTR error;
782 fileentry_t *fe = (fileentry_t *)pkt->dp_Arg1;
784 if (!fe)
785 return DOSFALSE;
787 if (fe->checknotify)
789 FSIZE size;
790 if (!CheckVolume(fe->le.volume, 1, &error, g))
791 return DOSFALSE;
792 UpdateLE((listentry_t *) fe, g);
793 Touch(&fe->le.info.file, g);
794 size = GetDEFileSize(fe->le.info.file.direntry, g);
795 if (fe->originalsize != size)
796 UpdateLinks(fe->le.info.file.direntry, g);
798 PFSDoNotify(&fe->le.info.file, TRUE, g);
799 fe->checknotify = 0;
802 RemoveListEntry((listentry_t *) fe, g);
803 return DOSTRUE;
806 static SIPTR dd_ChangeMode(struct DosPacket *pkt, globaldata * g)
808 // ARG1 = LONG type of object to change - either CHANGE_FH or CHANGE_LOCK
809 // ARG2 = BPTR object to be changed
810 // ARG3 = LONG new mode for object
811 // RES1 = Success/failure (DOSTRUE/DOSFALSE)
812 // RES2 = errorcode
814 listentry_t *listentry;
816 if (pkt->dp_Arg1 == CHANGE_FH)
817 listentry = (listentry_t *)
818 (((struct FileHandle *)BADDR(pkt->dp_Arg2))->fh_Arg1);
819 else
820 listentry = ListEntryFromLock(pkt->dp_Arg2);
822 if (listentry)
824 if (!CheckVolume(listentry->volume, 0, &pkt->dp_Res2, g))
825 return DOSFALSE;
827 UpdateLE(listentry, g);
829 else
830 return DOSFALSE;
832 return ChangeAccessMode(listentry, pkt->dp_Arg3, &pkt->dp_Res2);
835 /* reading and seeking in an open file */
836 static SIPTR dd_SeekRead(struct DosPacket *pkt, globaldata * g)
838 // ACTION_READ
839 // ARG1 = APTR fileentry. (filled in by Open())
840 // ARG2 = APTR buffer to put data into
841 // ARG3 = LONG #bytes to read
842 // RES1 = LONG #bytes read, 0=eof, -1=error
843 // RES2 = CODE failurecode if RES1=-1
845 // ACTION_SEEK
846 // ARG1 = APTR fileentry. (filled in by Open())
847 // ARG2 = LONG offset
848 // ARG3 = LONG seek mode
849 // RES1 = LONG absolute offset before seek
850 // RES2 = CODE failurecode if RES1=-1
852 listentry_t *listentry;
854 listentry = (listentry_t *) pkt->dp_Arg1;
855 if (!CheckVolume(listentry->volume, 0, &pkt->dp_Res2, g))
856 return -1;
858 UpdateLE(listentry, g);
860 if (pkt->dp_Type == ACTION_READ)
862 return (LONG)ReadFromObject((fileentry_t *) listentry,
863 (UBYTE *)pkt->dp_Arg2, (ULONG)pkt->dp_Arg3,
864 &pkt->dp_Res2, g);
866 else
868 return SeekInObject((fileentry_t *) listentry,
869 (LONG)pkt->dp_Arg2, (LONG)pkt->dp_Arg3,
870 &pkt->dp_Res2, g);
874 /* Write to an open file, or change its size (SFS = SetFileSize) */
875 static SIPTR dd_WriteSFS(struct DosPacket *pkt, globaldata * g)
877 // ACTION_WRITE
878 // ARG1 = APTR fileentry. (filled in by Open())
879 // ARG2 = APTR buffer to put data into
880 // ARG3 = LONG #bytes to read
881 // RES1 = LONG #bytes read, 0=eof, -1=error
882 // RES2 = CODE failurecode if RES1=-1
884 // ACTION_SET_FILE_SIZE
885 // ARG1 = APTR fileentry. (filled in by Open())
886 // ARG2 = LONG offset
887 // ARG3 = LONG mode
888 // RES1 = LONG new file size
889 // RES2 = CODE failurecode if RES1=-1
891 listentry_t *listentry;
893 listentry = (listentry_t *)pkt->dp_Arg1;
894 if (!CheckVolume(listentry->volume, 1, &pkt->dp_Res2, g))
895 return -1;
896 UpdateLE(listentry, g);
898 if (pkt->dp_Type == ACTION_WRITE)
900 return (LONG)WriteToObject((fileentry_t *)listentry,
901 (UBYTE *)pkt->dp_Arg2, (ULONG)pkt->dp_Arg3,
902 &pkt->dp_Res2, g);
904 else /* SetFileSize */
906 return ChangeObjectSize((fileentry_t *)listentry,
907 pkt->dp_Arg2, pkt->dp_Arg3, &pkt->dp_Res2, g);
912 /**********************
913 * Volume functions
916 /* change the name of a volume */
917 static SIPTR dd_Relabel(struct DosPacket *pkt, globaldata * g)
919 // ARG1 = BSTR new disk name
920 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
922 UBYTE newlabel[FNSIZE];
923 struct volumedata *volume;
924 struct DeviceList *devlist;
925 listentry_t *fe;
927 #if MULTIUSER
928 if (g->user->uid != muROOT_UID)
930 pkt->dp_Res2 = ERROR_DISK_WRITE_PROTECTED;
931 return DOSFALSE;
933 #endif
935 BCPLtoCString(newlabel, (DSTR)BARG1(pkt));
936 volume = g->currentvolume;
938 if (!CheckVolume(volume, 1, &pkt->dp_Res2, g))
939 return DOSFALSE;
941 /* make new doslist entry COPY VAN DISKINSERTSEQUENCE */
942 devlist = (struct DeviceList *)MakeDosEntry(newlabel, DLT_VOLUME);
943 if (devlist)
945 /* change rootblock */
946 if (RenameDisk(newlabel, g))
948 /* free old devlist */
949 // LockDosList (LDF_VOLUMES|LDF_READ);
950 Forbid();
951 RemDosEntry((struct DosList *)volume->devlist);
952 FreeDosEntry((struct DosList *)volume->devlist);
953 // UnLockDosList (LDF_VOLUMES|LDF_READ);
954 Permit();
956 /* fill in new. Diskname NIET */
957 g->currentvolume->devlist = devlist;
958 devlist->dl_Task = g->msgport;
959 devlist->dl_VolumeDate.ds_Days = volume->rootblk->creationday;
960 devlist->dl_VolumeDate.ds_Minute = volume->rootblk->creationminute;
961 devlist->dl_VolumeDate.ds_Tick = volume->rootblk->creationtick;
962 devlist->dl_LockList = BNULL; // disk still inserted
963 devlist->dl_DiskType = volume->rootblk->disktype;
965 /* toevoegen */
966 AddDosEntry((struct DosList *)devlist);
967 volume->devlist = (struct DeviceList *)devlist;
969 /* alle locks veranderen */
970 for (fe = HeadOf(&volume->fileentries); fe->next; fe = fe->next)
971 fe->lock.fl_Volume = MKBADDR(devlist);
973 else
975 pkt->dp_Res2 = ERROR_INVALID_COMPONENT_NAME;
976 return DOSFALSE;
979 else
981 pkt->dp_Res2 = ERROR_NO_FREE_STORE; // ??
982 return DOSFALSE;
985 return DOSTRUE;
988 /* change the size of the cache */
989 static SIPTR dd_AddBuffers(struct DosPacket *pkt, globaldata * g)
991 // ARG1 = LONG (number of buffers)
992 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
993 // RES2 = new total number of cache buffers or failurecode (if res1 = DOSFALSE)
995 struct lru_cachedblock *lrunode, *nextnode;
996 LONG numbuffers;
998 /* kill old cache */
999 UpdateDisk(g);
1001 for (lrunode = (struct lru_cachedblock *)g->glob_lrudata.LRUqueue.mlh_Head; lrunode->next;
1002 lrunode = nextnode)
1004 FlushBlock(&lrunode->cblk, g);
1005 nextnode = lrunode->next;
1006 MinRemove(lrunode);
1009 DeallocLRU(g);
1010 numbuffers = g->dosenvec->de_NumBuffers;
1011 numbuffers = max(0, numbuffers + (LONG)pkt->dp_Arg1);
1012 g->dosenvec->de_NumBuffers = numbuffers;
1014 while (!InitLRU(g, SIZEOF_RESBLOCK))
1015 g->dosenvec->de_NumBuffers--;
1017 pkt->dp_Res2 = g->dosenvec->de_NumBuffers;
1018 return (LONG)g->dosenvec->de_NumBuffers;
1021 /* disk info */
1022 static SIPTR dd_Info(struct DosPacket *pkt, globaldata * g)
1024 // ARG1 = diskinfo: BPTR to InfoData to fill in
1025 // info: BPTR lock on volume
1026 // ARG2 = info: BPTR to InfoData to fill in
1027 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
1029 struct InfoData *info;
1030 lockentry_t *le;
1031 struct volumedata *volume;
1033 ENTER("dd_info");
1034 if (pkt->dp_Type == ACTION_DISK_INFO)
1036 info = (struct InfoData *)BARG1(pkt);
1037 volume = g->currentvolume;
1039 else
1041 le = LockEntryFromLock(pkt->dp_Arg1);
1042 volume = le ? (le->le.volume) : (g->currentvolume);
1043 if (volume != g->currentvolume)
1045 pkt->dp_Res2 = ERROR_DEVICE_NOT_MOUNTED;
1046 return DOSFALSE;
1048 info = (struct InfoData *)BARG2(pkt);
1051 if (volume)
1053 info->id_NumSoftErrors = volume->numsofterrors;
1054 info->id_UnitNumber = g->startup->fssm_Unit;
1055 info->id_DiskState = g->softprotect ? ID_WRITE_PROTECTED : g->diskstate;
1056 info->id_NumBlocks = volume->numblocks - g->rootblock->lastreserved
1057 - g->rootblock->alwaysfree - 1;
1058 info->id_NumBlocksUsed = info->id_NumBlocks - alloc_data.alloc_available;
1059 info->id_BytesPerBlock = volume->bytesperblock;
1060 #ifdef KS13WRAPPER
1061 // 1.x C:Info only understands DOS\0
1062 info->id_DiskType = DOSBase->dl_lib.lib_Version >= 37 ? ID_INTER_FFS_DISK : ID_DOS_DISK;
1063 #else
1064 info->id_DiskType = ID_INTER_FFS_DISK; // c:Info does not like this
1065 #endif
1066 info->id_VolumeNode = MKBADDR(volume->devlist);
1067 info->id_InUse = !IsMinListEmpty(&volume->fileentries);
1069 return DOSTRUE;
1071 else
1073 info->id_NumSoftErrors = 0;
1074 info->id_UnitNumber = g->startup->fssm_Unit;
1075 info->id_DiskState = g->diskstate;
1076 info->id_NumBlocks = g->geom->dg_TotalSectors - 2;
1077 info->id_NumBlocksUsed = 0;
1078 info->id_BytesPerBlock = g->geom->dg_SectorSize;
1079 info->id_DiskType = g->disktype;
1080 info->id_VolumeNode = 0;
1081 info->id_InUse = 0;
1083 return DOSTRUE;
1087 /* flush cache (BTW: doesn't actually flush the cache right now) */
1088 static SIPTR dd_Flush(struct DosPacket *pkt, globaldata * g)
1090 UpdateDisk(g);
1091 FreeUnusedResources(g->currentvolume, g);
1092 g->timeout = 0;
1093 return DOSTRUE;
1096 /* soft-writeprotect disk */
1097 static SIPTR dd_WriteProtect(struct DosPacket *pkt, globaldata * g)
1099 // ARG1 = BOOL DOSTRUE = write protect; DOSFALSE = un-writeprotect
1100 // ARG2 = LONG 32 bit pass key
1101 // RES1 = Success/failure (DOSTRUE/DOSFALSE)
1103 if (pkt->dp_Arg1) /* protecting */
1105 if (g->softprotect) /* already protected */
1106 return DOSFALSE;
1107 UpdateDisk(g);
1108 /* updatedisk can cause a softprotect, so check again */
1109 if (!g->softprotect)
1111 g->softprotect = 1;
1112 g->protectkey = pkt->dp_Arg2;
1114 return DOSTRUE;
1116 else /* un protecting */
1118 if (!g->softprotect)
1119 return DOSTRUE;
1120 if (g->softprotect < 0)
1121 return DOSFALSE;
1123 if (!g->protectkey || g->protectkey == pkt->dp_Arg2 ||
1124 g->protectkey == ~0)
1126 g->softprotect = 0;
1127 g->protectkey = 0;
1128 return DOSTRUE;
1130 return DOSFALSE;
1134 /* make disk unique by timestamping it */
1135 static SIPTR dd_SerializeDisk(struct DosPacket *pkt, globaldata * g)
1137 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
1138 // RES2 = failurecode (if res1 = DOSFALSE)
1139 struct DateStamp time;
1140 struct rootblock *rbl;
1142 DateStamp(&time);
1144 /* bitmap is not needed, so read just bear rootblock */
1145 if (!(rbl = AllocBufmem(BLOCKSIZE, g)))
1147 pkt->dp_Res2 = ERROR_NO_FREE_STORE;
1148 return DOSFALSE;
1151 pkt->dp_Res2 = RawRead((UBYTE *)rbl, 1, ROOTBLOCK, g);
1152 if (pkt->dp_Res2)
1153 goto inh_error;
1155 /* Adding 3 to the tick prevents problems after format */
1156 rbl->creationday = (UWORD)time.ds_Days;
1157 rbl->creationminute = (UWORD)time.ds_Minute;
1158 rbl->creationtick = (UWORD)time.ds_Tick + 3;
1159 pkt->dp_Res2 = RawWrite((UBYTE *)rbl, 1, ROOTBLOCK, g);
1160 if (pkt->dp_Res2)
1161 goto inh_error;
1163 g->request->iotd_Req.io_Command = CMD_UPDATE;
1164 DoIO((struct IORequest *)g->request);
1165 FreeBufmem(rbl, g);
1166 return DOSTRUE;
1168 inh_error:
1169 FreeBufmem(rbl, g);
1170 return DOSFALSE;
1174 /**********************
1175 * Object functions
1177 static SIPTR dd_DeleteObject(struct DosPacket *pkt, globaldata * g)
1179 // ARG1 = Lock to which ARG2 is relative (BPTR)
1180 // ARG2 = BSTR Name of object to be deleted
1181 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
1182 // RES2 = failurecode (if res1 = DOSFALSE)
1184 lockentry_t *parentfe;
1185 union objectinfo *parentfi, filefi;
1186 UBYTE *filename, pathname[PATHSIZE];
1187 SIPTR *error = &pkt->dp_Res2;
1188 #if MULTIUSER
1189 struct extrafields extrafields;
1190 ULONG flags;
1191 #endif
1193 GetFileInfoFromLock(pkt->dp_Arg1, 1, parentfe, parentfi);
1194 BCPLtoCString(pathname, (DSTR)BARG2(pkt));
1195 SkipColon(filename, pathname);
1196 LocateFile(parentfi, filename, filefi, error);
1198 #if MULTIUSER
1199 #if DELDIR
1200 GetExtraFieldsOI(&filefi, &extrafields, g);
1201 #else /* DELDIR */
1202 GetExtraFields(filefi.file.direntry, &extrafields);
1203 #endif /* DELDIR */
1204 flags = muGetRelationship(extrafields);
1205 if (*error = muFS_CheckDeleteAccess(extrafields.prot, flags, g))
1206 return DOSFALSE;
1207 #endif /* MULTIUSER */
1209 PFSDoNotify(&filefi.file, TRUE, g);
1210 return DeleteObject(&filefi, &pkt->dp_Res2, g);
1213 static SIPTR dd_Rename(struct DosPacket *pkt, globaldata * g)
1215 // ARG1 = BPTR Lock to which ARG2 is relative
1216 // ARG2 = BSTR Name of object to rename
1217 // ARG3 = BPTR Lock to target directory
1218 // ARG4 = BSTR New name of object
1219 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
1220 // RES2 = failurecode (if res1 = DOSFALSE)
1222 lockentry_t *srcdirfe, *dstdirfe;
1223 union objectinfo *srcdirfi, *dstdirfi;
1224 UBYTE *srcname, srcpathname[PATHSIZE], *dstname, dstpathname[PATHSIZE];
1225 struct volumedata *srcvol, *dstvol;
1226 SIPTR *error = &pkt->dp_Res2;
1227 union objectinfo pathoi, sourceoi;
1228 UBYTE *objectname;
1229 BOOL result;
1230 #if MULTIUSER
1231 struct extrafields extrafields;
1232 ULONG flags;
1233 #endif
1235 GetFileInfoFromLock(pkt->dp_Arg1, 1, srcdirfe, srcdirfi);
1236 GetFileInfoFromLock(pkt->dp_Arg3, 1, dstdirfe, dstdirfi);
1237 BCPLtoCString(srcpathname, (DSTR)BARG2(pkt));
1238 BCPLtoCString(dstpathname, (DSTR)BARG4(pkt));
1239 DB(Trace(1, "Rename", "renaming %s to %s\n", srcpathname, dstpathname));
1241 SkipColon(srcname, srcpathname);
1242 SkipColon(dstname, dstpathname);
1244 /* check rename across devices (NOT needed; done by DOS */
1245 srcvol = srcdirfe ? srcdirfe->le.volume : g->currentvolume;
1246 dstvol = dstdirfe ? dstdirfe->le.volume : g->currentvolume;
1247 if (srcvol != dstvol)
1249 *error = ERROR_RENAME_ACROSS_DEVICES;
1250 return DOSFALSE;
1252 else
1254 #if MU_CHECKDIR
1255 --> check source AND destination directories against write access
1256 #endif /* MU_CHECKDIR */
1258 if (!(objectname = GetFullPath (srcdirfi, srcname, &pathoi, error, g)) ||
1259 !FindObject (&pathoi, objectname, &sourceoi, error, g))
1260 return DOSFALSE;
1262 CheckPropertyAccess (sourceoi, extrafields, flags, error);
1263 if (!CheckVolume(srcvol, 1, error, g))
1264 return DOSFALSE;
1265 else
1267 result = RenameAndMove (&pathoi, &sourceoi, dstdirfi, dstname,
1268 error, g);
1269 return result;
1274 /* change a object property: filenote, protection, owner, date */
1275 static SIPTR dd_SetProperty(struct DosPacket *pkt, globaldata * g)
1277 // ARG1 = Unused
1278 // ARG2 = BPTR Lock to which arg3 is relative
1279 // ARG3 = BSTR Name of object
1280 // ARG4 = LONG new property
1281 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
1282 // RES2 = failurecode (if res1 = DOSFALSE)
1284 lockentry_t *parentfe;
1285 union objectinfo *parentfi, objectfi;
1286 SIPTR *error = &pkt->dp_Res2;
1287 UBYTE *filename, pathname[PATHSIZE], comment[PATHSIZE];
1288 #if MULTIUSER
1289 struct extrafields extrafields;
1290 ULONG flags;
1291 #endif
1293 GetFileInfoFromLock(pkt->dp_Arg2, 1, parentfe, parentfi);
1294 BCPLtoCString(pathname, (DSTR)BARG3(pkt));
1295 SkipColon(filename, pathname);
1296 LocateFile(parentfi, filename, objectfi, error);
1297 CheckPropertyAccess(objectfi, extrafields, flags, error);
1298 PFSDoNotify(&objectfi.file, TRUE, g);
1300 switch (pkt->dp_Type)
1302 case ACTION_SET_PROTECT:
1303 return ProtectFile(&objectfi.file, (ULONG)pkt->dp_Arg4, error, g);
1305 case ACTION_SET_COMMENT:
1306 BCPLtoCString(comment, (DSTR)BARG4(pkt));
1307 return AddComment(&objectfi, comment, error, g);
1309 case ACTION_SET_DATE:
1310 return SetDate(&objectfi, (struct DateStamp *)pkt->dp_Arg4, error, g);
1312 case ACTION_SET_OWNER:
1313 return SetOwnerID(&objectfi.file, pkt->dp_Arg4, error, g);
1316 return DOSFALSE;
1320 * Examine directory contents
1322 static SIPTR dd_Examine(struct DosPacket *pkt, globaldata * g)
1324 // ARG1 = LOCK or filehandle of object to examine
1325 // ARG2 = BPTR FileInfoBlock to fill in
1326 // RES1 = Success/failure (DOSTRUE/DOSFALSE)
1327 // RES2 = errorcode
1329 listentry_t *listentry;
1331 if (pkt->dp_Type == ACTION_EXAMINE_FH)
1332 listentry = (listentry_t *) pkt->dp_Arg1;
1333 else
1334 listentry = ListEntryFromLock(pkt->dp_Arg1);
1336 if (listentry)
1338 if (!CheckVolume(listentry->volume, 0, &pkt->dp_Res2, g))
1339 return DOSFALSE;
1341 UpdateLE(listentry, g);
1342 UpdateLE_exa((lockentry_t *) listentry, g);
1344 else if (!g->currentvolume)
1346 pkt->dp_Res2 = ERROR_NO_DISK;
1347 return DOSFALSE;
1350 if (pkt->dp_Type == ACTION_EXAMINE_NEXT)
1351 return ExamineNextFile((lockentry_t *) listentry,
1352 (struct FileInfoBlock *)BARG2(pkt),
1353 &pkt->dp_Res2, g);
1354 else
1355 return ExamineFile(listentry,
1356 (struct FileInfoBlock *)BARG2(pkt),
1357 &pkt->dp_Res2, g);
1360 static SIPTR dd_ExamineAll(struct DosPacket *pkt, globaldata * g)
1362 // ARG1 = BPTR Lock on directory to examine
1363 // ARG2 = APTR Buffer to store resultsobject to be changed
1364 // ARG3 = LONG Length (in bytes) of buffer (arg2)
1365 // ARG4 = LONG Type of request
1366 // ARG5 = APTR (!!) Control structure to store information
1367 // RES1 = Continuation-flag - DOSFALSE indicates termination
1368 // RES2 = Failure code if RES1 is DOSFALSE
1370 listentry_t *listentry;
1371 DB(Trace(1, "ExamineAll", "1: %lx 2: %lx 3: %ld 4: %ld 5: %lx\n", pkt->dp_Arg1, pkt->dp_Arg2,
1372 pkt->dp_Arg3, pkt->dp_Arg4, pkt->dp_Arg5));
1374 listentry = ListEntryFromLock(pkt->dp_Arg1);
1375 if (listentry)
1377 if (!CheckVolume(listentry->volume, 0, &pkt->dp_Res2, g))
1378 return DOSFALSE;
1380 UpdateLE(listentry, g);
1381 UpdateLE_exa((lockentry_t *) listentry, g);
1383 else if (!g->currentvolume)
1385 pkt->dp_Res2 = ERROR_NO_DISK;
1386 return DOSFALSE;
1389 return ExamineAll((lockentry_t *)listentry,
1390 (UBYTE *)pkt->dp_Arg2, (ULONG)pkt->dp_Arg3, pkt->dp_Arg4,
1391 (struct ExAllControl *)(pkt->dp_Arg5),
1392 &pkt->dp_Res2, g);
1395 /* make a hard or softlink */
1396 static SIPTR dd_MakeLink(struct DosPacket *pkt, globaldata * g)
1398 // ARG1 = BPTR LOCK on directory ARG2 is relative to
1399 // ARG2 = BSTR Name of link
1400 // ARG3 = BPTR FileLock (LINK_HARD)
1401 // const char * (LINK_SOFT)
1402 // ARG4 = LONG type of link
1403 // RES1 = success
1404 // RES2 = failure code
1406 lockentry_t *parentle, *targetle;
1407 union objectinfo path, linkinfo, *parentfi;
1408 UBYTE linkname[PATHSIZE];
1409 UBYTE *zonderpad, *fullname;
1410 BOOL result;
1411 #if MULTIUSER
1412 #if MU_CHECKDIR
1413 struct extrafields extrafields;
1414 ULONG flags;
1415 #endif
1416 #endif
1417 SIPTR *error = &pkt->dp_Res2;
1419 GetFileInfoFromLock(pkt->dp_Arg1, 1, parentle, parentfi);
1420 BCPLtoCString(linkname, (DSTR)BARG2(pkt));
1421 SkipColon(fullname, linkname);
1423 if (!(zonderpad = GetFullPath(parentfi, fullname, &path, &pkt->dp_Res2, g)))
1424 return DOSFALSE;
1426 #if MULTIUSER
1427 #if MU_CHECKDIR
1428 if (!IsVolume(path))
1430 #if DELDIR
1431 GetExtraFieldsOI(&path, &extrafields);
1432 #else /* DELDIR */
1433 GetExtraFields(path.file.direntry, &extrafields);
1434 #endif /* DELDIR */
1435 flags = muGetRelationship(extrafields);
1436 if (pkt->dp_Res2 = muFS_CheckWriteAccess(extrafields.prot, flags, g))
1437 return DOSFALSE;
1439 #endif /* MU_CHECKDIR */
1440 #endif /* MULTIUSER */
1444 * Arg4 sometimes seems to be -1 instead of 1 when softlinks are meant,
1445 * so I will treat everything not LINK_HARD as LINK_SOFT
1447 if (pkt->dp_Arg4 != LINK_HARD)
1449 result = CreateSoftLink(&path, zonderpad, (STRPTR) pkt->dp_Arg3, &linkinfo,
1450 &pkt->dp_Res2, g);
1451 if (result)
1452 PFSDoNotify(&linkinfo.file, TRUE, g);
1454 return result;
1457 /* check if lock is ours (it could be alien) */
1458 targetle = LockEntryFromLock(pkt->dp_Arg3);
1459 if (!targetle || (BADDR(targetle->le.lock.fl_Volume) != g->currentvolume->devlist))
1461 pkt->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
1462 return DOSFALSE;
1465 /* don't do this until you know the lock is ours */
1466 UpdateLE((listentry_t *)targetle, g);
1468 result = CreateLink(&path, zonderpad, &targetle->le.info, &linkinfo, &pkt->dp_Res2, g);
1469 if (result)
1471 PFSUpdateNotify(linkinfo.file.dirblock->blk.anodenr, zonderpad,
1472 targetle->le.info.file.direntry->anode, g);
1473 PFSDoNotify(&linkinfo.file, TRUE, g);
1476 return result;
1479 /* read a softlink: finding out which file (ascii) it is referring to */
1480 static SIPTR dd_ReadLink(struct DosPacket *pkt, globaldata * g)
1482 // ARG1 = BPTR LOCK on directory ARG2 is relative to
1483 // ARG2 = BSTR Name of link
1484 // ARG3 = STRPTR buffer to store result
1485 // ARG4 = ULONG size of buffer
1486 // RES1 = success
1487 // RES2 = failure code
1489 lockentry_t *parentle;
1490 union objectinfo linkfi, *parentfi;
1491 char *fullname;
1492 SIPTR *error = &pkt->dp_Res2;
1494 GetFileInfoFromLock(pkt->dp_Arg1, 0, parentle, parentfi);
1496 /* strip upto first : */
1497 SkipColon(fullname, (char *)pkt->dp_Arg2);
1499 if (!(FindObject(parentfi, fullname, &linkfi,
1500 &pkt->dp_Res2, g)))
1502 if (pkt->dp_Res2 != ERROR_IS_SOFT_LINK)
1503 return DOSFALSE;
1506 return ReadSoftLink(&linkfi, (char *)pkt->dp_Arg3, pkt->dp_Arg4, &pkt->dp_Res2, g);
1510 /**********************
1511 * goto inhibited state
1514 /* inhibit called from uninhibited state */
1515 static SIPTR dd_InhibitOn(struct DosPacket *pkt, globaldata * g)
1517 // ARG1 = BOOL DOSTRUE = inhibit; DOSFALSE = uninhibit
1518 // RES1 = Success/failure (DOSTRUE/DOSFALSE)
1520 if (pkt->dp_Arg1 != DOSFALSE) /* don't check for DOSTRUE (Holger Kruse!) */
1522 while (g->currentvolume) /* inefficiënt.. */
1523 DiskRemoveSequence(g);
1524 g->inhibitcount++;
1525 g->timeron = FALSE;
1526 g->timeout = 0;
1527 g->DoCommand = InhibitedCommands;
1528 g->disktype = ID_BUSY;
1531 /* else ->already uninhibited */
1532 return DOSTRUE;
1535 /* Inhibit called from inhibited state */
1536 static SIPTR dd_InhibitOff(struct DosPacket *pkt, globaldata * g)
1538 // ARG1 = BOOL DOSTRUE = inhibit; DOSFALSE = uninhibit
1539 // RES1 = Success/failure (DOSTRUE/DOSFALSE)
1541 if (pkt->dp_Arg1 != DOSFALSE) /* don't check for DOSTRUE (Holger Kruse) */
1543 g->inhibitcount++;
1545 else
1547 g->inhibitcount--;
1548 if (g->inhibitcount <= 0)
1550 if (g->trackdisk)
1552 g->request->iotd_Req.io_Command = CMD_CLEAR;
1553 DoIO((struct IORequest *)g->request);
1556 g->DoCommand = NormalCommands;
1557 g->timeron = FALSE;
1558 NewVolume(TRUE, g);
1562 return DOSTRUE;
1566 static SIPTR dd_Format(struct DosPacket *pkt, globaldata * g)
1568 /* argumenten stemmen NIET met de dosmanual overeen */
1569 // ARG1 = BSTR Name of device (with trailing ':')
1570 // ARG2 = LONG Type of format (file system specific ==> ID_FDOS_DISK of 0)
1571 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
1572 // RES2 = failurecode (if res1 = DOSFALSE)
1574 #if MULTIUSER
1575 if (g->user->uid != muROOT_UID)
1577 pkt->dp_Res2 = ERROR_DISK_WRITE_PROTECTED;
1578 return DOSFALSE;
1580 #endif
1582 /* Ik neem aan dat er geen Lock check nodig is ... */
1583 /* if not inhibited then 'remove disk' */
1584 if (g->inhibitcount == 0)
1586 g->dirty = FALSE;
1587 while (g->currentvolume)
1588 DiskRemoveSequence(g); // should always succeed now
1592 /* format disk */
1593 return FDSFormat((DSTR)BADDR(pkt->dp_Arg1), pkt->dp_Arg2, &pkt->dp_Res2, g);
1597 /**********************
1598 * Notify stuff
1600 static SIPTR dd_AddNotify (struct DosPacket *pkt, globaldata *g)
1602 // ARG1 = APTR struct NotifyRequest *
1603 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
1604 // RES2 = failurecode (if res1 = DOSFALSE)
1606 struct NotifyRequest *nr = (struct NotifyRequest *)pkt->dp_Arg1;
1607 struct notifyobject *no;
1608 union objectinfo oi, filefi;
1609 char *name, *temp;
1610 BOOL found = FALSE;
1611 int t;
1613 if (!(no = AllocMemP (sizeof(struct notifyobject), g)))
1614 goto memerror1;
1616 /* strip upto first : */
1617 name = strchr (nr->nr_FullName, ':');
1618 if (name)
1619 name++;
1620 else
1621 name = nr->nr_FullName;
1623 /* search for notification object */
1624 no->req = nr;
1625 no->unparsed = NULL;
1626 temp = FilePart (name);
1627 t = strlen (temp);
1628 if (!(no->objectname = AllocMemP (t+2, g)))
1629 goto memerror2;
1630 ctodstr (temp, no->objectname);
1631 intltoupper (no->objectname);
1633 if (!(GetFullPath(NULL, name, &oi, &pkt->dp_Res2, g)))
1635 if (g->unparsed)
1637 temp = PathPart (g->unparsed);
1638 *temp = 0; /* cut of filepart */
1639 t = strlen (g->unparsed);
1640 if (!(no->unparsed = no->namemem = AllocMemP(t+2, g)))
1641 goto memerror3;
1642 ctodstr (g->unparsed, no->unparsed);
1643 intltoupper (no->unparsed);
1644 no->unparsed++; /* make it a cstring!! */
1646 else
1647 return DOSFALSE;
1649 else
1651 /* try to locate object */
1652 found = FindObject (&oi, no->objectname+1, &filefi, &pkt->dp_Res2, g);
1653 if (found)
1655 no->anodenr = IsVolume(filefi) ? ANODE_ROOTDIR : filefi.file.direntry->anode;
1659 #if DELDIR
1660 if (IsDelDir (oi))
1662 pkt->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
1663 return DOSFALSE;
1665 #endif
1667 /* set object id (anodenr) */
1668 if (IsVolume (oi))
1669 no->parentanodenr = ANODE_ROOTDIR;
1670 else
1671 no->parentanodenr = oi.file.direntry->anode;
1673 /* add notification to list */
1674 MinAddHead (&g->currentvolume->notifylist, no);
1676 /* do initial message, if necessary */
1677 if (found && (nr->nr_Flags & NRF_NOTIFY_INITIAL))
1678 NotifyUser (nr, g);
1680 return DOSTRUE;
1682 memerror3:
1683 FreeMemP (no->objectname, g);
1684 memerror2:
1685 FreeMemP (no, g);
1686 memerror1:
1687 pkt->dp_Res2 = ERROR_NO_FREE_STORE;
1688 return DOSFALSE;
1691 static SIPTR dd_RemoveNotify (struct DosPacket *pkt, globaldata * g)
1693 // ARG1 = APTR struct NotifyRequest *
1694 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
1695 // RES2 = failurecode (if res1 = DOSFALSE)
1697 struct NotifyRequest *nr = (struct NotifyRequest *)pkt->dp_Arg1;
1698 struct notifyobject *no;
1701 * BTW: pending messages that return after RemoveNotify
1702 * may cause trouble
1705 /* remove from queue */
1706 for (no = HeadOf(&g->currentvolume->notifylist); no->next; no = no->next)
1708 if (no->req == nr)
1710 MinRemove (no);
1711 FreeMemP (no->namemem, g);
1712 FreeMemP (no->objectname, g);
1713 FreeMemP (no, g);
1714 break;
1718 return DOSTRUE;
1722 /**********************
1723 * internal and PFS2 extended packets
1727 * Check if packet really is a PFS2 custom packet
1729 static int dd_CheckCustomPacket(LONG id)
1731 if (id == ID_PFS2_DISK || id == ID_AFS_DISK)
1732 return 1;
1733 else
1734 return 0;
1738 * Check if filesystem is PFS2
1740 static SIPTR dd_IsPFS2 (struct DosPacket *pkt, globaldata *g)
1742 // ARG1 = ID_PFS2_DISK
1743 // RES1 = DOSTRUE (is PFS2), otherwise it isn't
1744 // RES2 = Upper: version, Lower: revision
1746 if (!dd_CheckCustomPacket(pkt->dp_Arg1))
1748 return NotKnown (pkt, g);
1750 else
1752 pkt->dp_Res2 = (VERNUM<<16) + REVNUM;
1753 return DOSTRUE;
1758 * Remove empty file
1760 static SIPTR dd_KillEmpty(struct DosPacket *pkt, globaldata * g)
1762 // ARG1 = lock to parent directory
1763 // ARG2 = ID_PFS2_DISK or ID
1765 lockentry_t *parentfe;
1766 union objectinfo *parentfi;
1767 SIPTR *error = &pkt->dp_Res2;
1769 if (!dd_CheckCustomPacket(pkt->dp_Arg2))
1770 return DOSFALSE;
1772 GetFileInfoFromLock(pkt->dp_Arg1, 1, parentfe, parentfi);
1773 return KillEmpty(parentfi, g);
1778 * remove direntry, without freeing diskspace or checking
1779 * validity. Useful for corrupt files & entries.
1781 static SIPTR dd_RemoveDirEntry(struct DosPacket *pkt, globaldata * g)
1783 // ARG1 = ID_PFS2_DISK
1784 // ARG2 = Lock to which ARG2 is relative (BPTR)
1785 // ARG3 = STRPTR Name of object to be deleted
1786 // RES1 = BOOL Success/failure (DOSTRUE/DOSFALSE)
1787 // RES2 = failurecode (if res1 = DOSFALSE)
1789 lockentry_t *parentfe;
1790 union objectinfo *parentfi, filefi;
1791 UBYTE *filename, *pathname;
1792 SIPTR *error = &pkt->dp_Res2;
1794 if (!dd_CheckCustomPacket(pkt->dp_Arg1))
1795 return DOSFALSE;
1797 GetFileInfoFromLock(pkt->dp_Arg2, 1, parentfe, parentfi);
1798 pathname = (UBYTE *)pkt->dp_Arg3;
1799 SkipColon(filename, pathname);
1800 LocateFile(parentfi, filename, filefi, error);
1802 return forced_RemoveDirEntry(&filefi, &pkt->dp_Res2, g);
1805 #if EXTRAPACKETS
1808 * exit or leave SLEEP_MODE
1810 static SIPTR dd_Sleep(struct DosPacket *pkt, globaldata * g)
1812 // ARG1 = MODE_PFS2_DISK
1813 // ARG2 = on/off (DOSTRUE = on; DOSFALSE = off)
1814 // ARG3 = ULONG signalnr
1815 // ARG4 = struct Task *task
1816 // RES1 = struct MsgPort *sleepport or NULL for failure;
1817 // RES2 = errorcode
1819 if (!dd_CheckCustomPacket(pkt->dp_Arg1))
1820 return DOSFALSE;
1822 if (g->sleepmode)
1824 if (pkt->dp_Arg2 == DOSFALSE)
1826 Awake(g);
1827 g->sleeptask = NULL;
1828 g->alarmsignal = 0;
1829 return DOSTRUE;
1831 else
1833 pkt->dp_Res2 = ERROR_OBJECT_IN_USE; /* already locked */
1834 return DOSFALSE;
1837 else
1839 if (pkt->dp_Arg2 == DOSFALSE)
1840 return DOSFALSE;
1841 else
1843 g->sleeptask = (struct Task *)pkt->dp_Arg4;
1844 g->alarmsignal = (ULONG)pkt->dp_Arg3;
1845 Sleep(g);
1846 return (SIPTR)g->sleepport;
1852 * add or remove Idle message
1854 * ARG1 = MODE_PFS2_DISK
1855 * ARG2 = add/remove (DOSTRUE = add; DOSFALSE = remove)
1856 * ARG3 = ULONG signalnr (UPPER = read, LOWER = write)
1857 * remove: handle to remove
1858 * ARG4 = struct Task *task
1859 * RES1 = Idlehandle or DOSFALSE for failure
1860 * RES2 = errorcode
1862 static SIPTR dd_SignalIdle(struct DosPacket *pkt, globaldata * g)
1864 struct idlehandle *handle;
1866 if (!dd_CheckCustomPacket(pkt->dp_Arg1))
1867 return DOSFALSE;
1869 if (pkt->dp_Arg2 == DOSTRUE)
1871 handle = (struct idlehandle *)AllocMemP (sizeof(struct idlehandle), g);
1872 if (!handle)
1873 return DOSFALSE;
1875 handle->task = (struct Task *)pkt->dp_Arg4;
1876 handle->cleansignal = pkt->dp_Arg3 >> 16;
1877 handle->dirtysignal = pkt->dp_Arg3 & 0xffff;
1878 MinAddHead (&g->idlelist, handle);
1879 return (SIPTR)handle;
1881 else
1883 MinRemove (pkt->dp_Arg3);
1884 FreeMemP ((void *)pkt->dp_Arg3, g);
1885 return DOSTRUE;
1890 static SIPTR dd_UpdateAnode(struct DosPacket *pkt, globaldata * g)
1892 // ARG1 = MODE_PFS2_DISK
1893 // ARG2 = old anodenr
1894 // ARG3 = new anodenr (0 = invalidate references)
1895 // RES1 = updatecount or -1 for failure
1896 // RES2 = failurecode if Res1 = -1
1898 if (!dd_CheckCustomPacket(pkt->dp_Arg1))
1899 return -1;
1901 return UpdateAnode(pkt->dp_Arg2, pkt->dp_Arg3, g);
1903 #endif
1905 #if ROLLOVER
1906 static SIPTR dd_MakeRollover(struct DosPacket *pkt, globaldata * g)
1908 // ARG1 = MODE_PFS2_DISK
1909 // ARG2 = BPTR LOCK on directory ARG3 is relative to
1910 // ARG3 = APTR name of rollover file
1911 // ARG4 = WORD desired rollover size in blocks
1912 // RES1 = success
1913 // RES2 = failure code
1915 lockentry_t *parentle;
1916 union objectinfo path, rolloverinfo, *parentfi;
1917 UBYTE *rollovername;
1918 UBYTE *zonderpad, *fullname;
1919 SIPTR *error = &pkt->dp_Res2;
1920 BOOL result;
1922 if (!dd_CheckCustomPacket(pkt->dp_Arg1))
1923 return DOSFALSE;
1925 GetFileInfoFromLock(pkt->dp_Arg2, 1, parentle, parentfi);
1926 rollovername = (UBYTE *)pkt->dp_Arg3;
1927 SkipColon(fullname, rollovername);
1929 if (!(zonderpad = GetFullPath(parentfi, fullname, &path, error, g)))
1930 return DOSFALSE;
1932 result = CreateRollover(&path, zonderpad, (ULONG)pkt->dp_Arg4,
1933 &rolloverinfo, error, g);
1934 if (result)
1936 PFSDoNotify (&rolloverinfo.file, TRUE, g);
1939 return result;
1942 /* Read and set rollover info
1944 static SIPTR dd_SetRollover(struct DosPacket *pkt, globaldata *g)
1946 // ARG1 = MODE_PFS2_DISK
1947 // ARG2 = APTR fileentry (filled in by Open())
1948 // ARG3 = APTR struct rolloverinfo
1949 // RES1 = success
1950 // RES2 = failure code
1952 listentry_t *rlfile;
1953 SIPTR *error = &pkt->dp_Res2;
1955 if (!dd_CheckCustomPacket(pkt->dp_Arg1))
1956 return DOSFALSE;
1957 rlfile = (listentry_t *)pkt->dp_Arg2;
1958 if (!CheckVolume(rlfile->volume, 1, error, g))
1959 return 0;
1960 if ((*error = SetRollover((fileentry_t *)rlfile, (struct rolloverinfo *)pkt->dp_Arg3, g)))
1961 return DOSFALSE;
1962 return DOSTRUE;
1964 #endif
1966 #if DELDIR
1967 static SIPTR dd_SetDeldir(struct DosPacket *pkt, globaldata *g)
1969 // ARG1 = MODE_PFS2_DISK
1970 // ARG2 = number of deldirblocks wanted (0 = disable, -1 = check)
1971 // RES1 = success
1972 // RES2 = failure code
1974 SIPTR *error = &pkt->dp_Res2;
1976 if (!dd_CheckCustomPacket(pkt->dp_Arg1))
1977 return DOSFALSE;
1979 #if MULTIUSER
1980 if (g->user->uid != muROOT_UID)
1982 *error = ERROR_DISK_WRITE_PROTECTED;
1983 return DOSFALSE;
1985 #endif
1987 /* check if a volume is inserted */
1988 if (!CheckVolume(g->currentvolume, 1, error, g))
1989 return DOSFALSE;
1991 /* just an inquiry */
1992 if (pkt->dp_Arg2 == -1)
1994 *error = g->currentvolume->rblkextension->blk.deldirsize;
1995 return DOSTRUE;
1998 if ((*error = SetDeldir(pkt->dp_Arg2, g)))
1999 return DOSFALSE;
2001 return DOSTRUE;
2004 #endif
2006 /* set filename size. failure codes:
2007 * ACTION_BAD_NUMBER = grootte illegaal of kleiner dan huidig
2009 static SIPTR dd_SetFileSize(struct DosPacket *pkt, globaldata *g)
2011 // ACTION_SET_FNSIZE 2222
2012 // ARG1 = MODE_PFS2_DISK
2013 // ARG2 = New maximum filename size (0 = huidige waarde opvragen)
2014 // RES1 = success
2015 // RES2 = failure code / current or new fnsize
2017 if (!dd_CheckCustomPacket(pkt->dp_Arg1))
2018 return DOSFALSE;
2020 if (pkt->dp_Arg2)
2022 if (pkt->dp_Arg2 < 30 || pkt->dp_Arg2 < FILENAMESIZE)
2024 pkt->dp_Res2 = ERROR_BAD_NUMBER;
2025 return DOSFALSE;
2028 if (pkt->dp_Arg2 >= FNSIZE)
2030 pkt->dp_Res2 = ERROR_OBJECT_TOO_LARGE;
2031 return DOSFALSE;
2035 if (g->currentvolume && g->currentvolume->rblkextension)
2037 if (pkt->dp_Arg2)
2039 g->rootblock->options |= MODE_LONGFN;
2040 g->fnsize = g->currentvolume->rblkextension->blk.fnsize = pkt->dp_Arg2;
2041 g->dirty = TRUE;
2043 pkt->dp_Res2 = g->fnsize;
2044 return DOSTRUE;
2047 pkt->dp_Res2 = ERROR_NO_DISK;
2048 return DOSFALSE;
2051 #if defined(__MORPHOS__)
2052 static LONG dd_MorphOSQueryAttr(struct DosPacket *pkt, globaldata *g)
2054 // ACTION_QUERY_ATTR 26407
2055 // ARG1 = LONG attr, which attribute you want to know about
2056 // ARG2 = void *storage, memory to hold the return value
2057 // ARG3 = LONG storagesize, size of storage reserved for
2058 // RES1 = success
2059 // RES2 = failure code
2060 // ERROR_BAD_NUMBER for unimplemented/unknown attributes
2061 // ERROR_LINE_TOO_LONG for buffer too small to hold the result
2063 APTR storage = (APTR) pkt->dp_Arg2;
2064 LONG storage_size = pkt->dp_Arg3;
2066 switch (pkt->dp_Arg1)
2068 case FQA_MaxFileNameLength:
2069 if (storage_size >= sizeof(LONG))
2071 *(LONG *)storage = FILENAMESIZE - 1;
2072 return DOSTRUE;
2074 break;
2076 case FQA_MaxVolumeNameLength:
2077 if (storage_size >= sizeof(LONG))
2079 *(LONG *)storage = DNSIZE - 1;
2080 return DOSTRUE;
2082 break;
2084 case FQA_IsCaseSensitive:
2085 if (storage_size >= sizeof(LONG))
2087 *(LONG *)storage = FALSE;
2088 return DOSTRUE;
2090 break;
2092 case FQA_MaxFileSize:
2093 if (storage_size >= sizeof(QUAD))
2095 *(QUAD *)storage = 0x7fffffffLL;
2096 return DOSTRUE;
2098 break;
2100 /* let dos.library handle these - fall thru */
2101 case FQA_DeviceType:
2102 case FQA_NumBlocks:
2103 case FQA_NumBlocksUsed:
2105 /* unknown/unhandled attribute */
2106 default:
2107 pkt->dp_Res2 = ERROR_BAD_NUMBER;
2108 return DOSFALSE;
2111 /* Not enough buffer storage */
2112 pkt->dp_Res2 = ERROR_LINE_TOO_LONG;
2113 return DOSFALSE;
2115 #endif
2117 #if EXTENDED_PACKETS_OS4
2119 #define DP64_INIT -3
2120 /* Not real one but close enough */
2121 struct DosPacket64OS4
2123 ULONG dp_Link;
2124 ULONG dp_Port;
2125 LONG dp_Type;
2126 ULONG dp_Res0;
2127 ULONG dp_Res2;
2128 QUAD dp_Res1;
2129 QUAD dp_Arg1;
2130 QUAD dp_Arg2;
2131 ULONG dp_Arg3;
2132 ULONG dp_Arg4;
2133 ULONG dp_Arg5;
2136 static listentry_t *InitOS464(struct DosPacket *pkt, globaldata *g, BOOL errortype)
2138 struct DosPacket64OS4 *dp = (struct DosPacket64OS4*)pkt;
2139 listentry_t *listentry;
2141 dp->dp_Res0 = DP64_INIT;
2142 dp->dp_Res2 = 0;
2143 listentry = (listentry_t *) pkt->dp_Arg1;
2144 if (!CheckVolume(listentry->volume, 0, &pkt->dp_Res2, g)) {
2145 dp->dp_Res1 = errortype ? -1 : 0;
2146 dp->dp_Res2 = ERROR_INVALID_LOCK;
2147 return NULL;
2149 UpdateLE(listentry, g);
2150 if (!IsFile(listentry->info)) {
2151 dp->dp_Res1 = errortype ? -1 : 0;
2152 dp->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
2153 return NULL;
2155 return listentry;
2158 static void dd_GetFileSize64(struct DosPacket *pkt, globaldata *g)
2160 struct DosPacket64OS4 *dp = (struct DosPacket64OS4*)pkt;
2161 listentry_t *listentry;
2163 listentry = InitOS464(pkt, g, TRUE);
2164 if (!listentry)
2165 return;
2166 dp->dp_Res1 = GetDEFileSize(listentry->info.file.direntry, g);
2169 static void dd_ChangeFileSize64(struct DosPacket *pkt, globaldata *g)
2171 struct DosPacket64OS4 *dp = (struct DosPacket64OS4*)pkt;
2172 listentry_t *listentry;
2173 LONG error;
2174 SFSIZE pos;
2176 listentry = InitOS464(pkt, g, FALSE);
2177 if (!listentry)
2178 return;
2179 pos = ChangeFileSize((fileentry_t *)listentry, dp->dp_Arg2, dp->dp_Arg3, &error, g);
2180 if (pos < 0) {
2181 dp->dp_Res1 = DOSFALSE;
2182 dp->dp_Res2 = error;
2183 } else {
2184 dp->dp_Res1 = DOSTRUE;
2188 static void dd_GetFilePosition64(struct DosPacket *pkt, globaldata *g)
2190 struct DosPacket64OS4 *dp = (struct DosPacket64OS4*)pkt;
2191 listentry_t *listentry;
2192 LONG error;
2193 SFSIZE pos;
2195 listentry = InitOS464(pkt, g, TRUE);
2196 if (!listentry)
2197 return;
2198 pos = SeekInObject((fileentry_t *)listentry, OFFSET_CURRENT, 0, &error, g);
2199 if (pos < 0) {
2200 dp->dp_Res1 = -1;
2201 dp->dp_Res2 = error;
2202 } else {
2203 dp->dp_Res1 = pos;
2207 static void dd_ChangeFilePosition64(struct DosPacket *pkt, globaldata *g)
2209 struct DosPacket64OS4 *dp = (struct DosPacket64OS4*)pkt;
2210 listentry_t *listentry;
2211 LONG error;
2212 SFSIZE pos;
2214 listentry = InitOS464(pkt, g, FALSE);
2215 if (!listentry)
2216 return;
2217 pos = SeekInObject((fileentry_t *)listentry, dp->dp_Arg3, dp->dp_Arg2, &error, g);
2218 if (pos < 0) {
2219 dp->dp_Res1 = DOSFALSE;
2220 dp->dp_Res2 = error;
2221 } else {
2222 dp->dp_Res1 = DOSTRUE;
2227 #endif