This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
44860c910175a201f09644d7e5f143ca59cd71bf
[perl5.git] / amigaos4 / amigaos.c
1 /* amigaos.c uses only amigaos APIs,
2  * as opposed to amigaio.c which mixes amigaos and perl APIs */
3
4 #include <string.h>
5
6 #include <sys/stat.h>
7 #include <unistd.h>
8 #include <assert.h>
9
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #if defined(__CLIB2__)
14 #  include <dos.h>
15 #endif
16 #if defined(__NEWLIB__)
17 #  include <amiga_platform.h>
18 #endif
19 #include <fcntl.h>
20 #include <ctype.h>
21 #include <stdarg.h>
22 #include <stdbool.h>
23 #undef WORD
24 #define WORD int16
25
26 #include <dos/dos.h>
27 #include <proto/dos.h>
28 #include <proto/exec.h>
29 #include <proto/utility.h>
30
31 #include "amigaos.h"
32
33 struct UtilityIFace *IUtility = NULL;
34
35 /***************************************************************************/
36
37 struct Interface *OpenInterface(CONST_STRPTR libname, uint32 libver)
38 {
39         struct Library *base = IExec->OpenLibrary(libname, libver);
40         struct Interface *iface = IExec->GetInterface(base, "main", 1, NULL);
41         if (iface == NULL)
42         {
43                 // We should probably post some kind of error message here.
44
45                 IExec->CloseLibrary(base);
46         }
47
48         return iface;
49 }
50
51 /***************************************************************************/
52
53 void CloseInterface(struct Interface *iface)
54 {
55         if (iface != NULL)
56         {
57                 struct Library *base = iface->Data.LibBase;
58                 IExec->DropInterface(iface);
59                 IExec->CloseLibrary(base);
60         }
61 }
62
63 BOOL __unlink_retries = FALSE;
64
65 void ___makeenviron() __attribute__((constructor));
66 void ___freeenviron() __attribute__((destructor));
67
68 void ___openinterfaces() __attribute__((constructor));
69 void ___closeinterfaces() __attribute__((destructor));
70
71 void ___openinterfaces()
72 {
73         if (!IDOS)
74                 IDOS = (struct DOSIFace *)OpenInterface("dos.library", 53);
75         if (!IUtility)
76                 IUtility =
77                     (struct UtilityIFace *)OpenInterface("utility.library", 53);
78 }
79
80 void ___closeinterfaces()
81 {
82         CloseInterface((struct Interface *)IDOS);
83         CloseInterface((struct Interface *)IUtility);
84 }
85 int VARARGS68K araddebug(UBYTE *fmt, ...);
86 int VARARGS68K adebug(UBYTE *fmt, ...);
87
88 #define __USE_RUNCOMMAND__
89
90 char **myenviron = NULL;
91 char **origenviron = NULL;
92
93 static void createvars(char **envp);
94
95 struct args
96 {
97         BPTR seglist;
98         int stack;
99         char *command;
100         int length;
101         int result;
102         char **envp;
103 };
104
105 int __myrc(__attribute__((unused))char *arg)
106 {
107         struct Task *thisTask = IExec->FindTask(0);
108         struct args *myargs = (struct args *)thisTask->tc_UserData;
109         if (myargs->envp)
110                 createvars(myargs->envp);
111         // adebug("%s %ld %s \n",__FUNCTION__,__LINE__,myargs->command);
112         myargs->result = IDOS->RunCommand(myargs->seglist, myargs->stack,
113                                           myargs->command, myargs->length);
114         return 0;
115 }
116
117 int32 myruncommand(
118     BPTR seglist, int stack, char *command, int length, char **envp)
119 {
120         struct args myargs;
121         struct Task *thisTask = IExec->FindTask(0);
122         struct Process *proc;
123
124         // adebug("%s %ld  %s\n",__FUNCTION__,__LINE__,command?command:"NULL");
125
126         myargs.seglist = seglist;
127         myargs.stack = stack;
128         myargs.command = command;
129         myargs.length = length;
130         myargs.result = -1;
131         myargs.envp = envp;
132
133         if ((proc = IDOS->CreateNewProcTags(
134                         NP_Entry, __myrc, NP_Child, TRUE, NP_Input, IDOS->Input(),
135                         NP_Output, IDOS->Output(), NP_Error, IDOS->ErrorOutput(),
136                         NP_CloseInput, FALSE, NP_CloseOutput, FALSE, NP_CloseError,
137                         FALSE, NP_CopyVars, FALSE,
138
139                         //           NP_StackSize,           ((struct Process
140                         //           *)myargs.parent)->pr_StackSize,
141                         NP_Cli, TRUE, NP_UserData, (int)&myargs,
142                         NP_NotifyOnDeathSigTask, thisTask, TAG_DONE)))
143
144         {
145                 IExec->Wait(SIGF_CHILD);
146         }
147         return myargs.result;
148 }
149
150 char *mystrdup(const char *s)
151 {
152         char *result = NULL;
153         size_t size;
154
155         size = strlen(s) + 1;
156
157         if ((result = (char *)IExec->AllocVecTags(size, TAG_DONE)))
158         {
159                 memmove(result, s, size);
160         }
161         return result;
162 }
163
164 static unsigned int pipenum = 0;
165
166 int pipe(int filedes[2])
167 {
168         char pipe_name[1024];
169
170 //   adebug("%s %ld \n",__FUNCTION__,__LINE__);
171 #ifdef USE_TEMPFILES
172         sprintf(pipe_name, "/T/%x.%08lx", pipenum++, IUtility->GetUniqueID());
173 #else
174         sprintf(pipe_name, "/PIPE/%x%08lx/4096/0", pipenum++,
175                 IUtility->GetUniqueID());
176 #endif
177
178         /*      printf("pipe: %s \n", pipe_name);*/
179
180         filedes[1] = open(pipe_name, O_WRONLY | O_CREAT);
181         filedes[0] = open(pipe_name, O_RDONLY);
182         if (filedes[0] == -1 || filedes[1] == -1)
183         {
184                 if (filedes[0] != -1)
185                         close(filedes[0]);
186                 if (filedes[1] != -1)
187                         close(filedes[1]);
188                 return -1;
189         }
190         /*      printf("filedes %d %d\n", filedes[0],
191          * filedes[1]);fflush(stdout);*/
192
193         return 0;
194 }
195
196 int fork(void)
197 {
198         fprintf(stderr, "Can not bloody fork\n");
199         errno = ENOMEM;
200         return -1;
201 }
202
203 int wait(__attribute__((unused))int *status)
204 {
205         fprintf(stderr, "No wait try waitpid instead\n");
206         errno = ECHILD;
207         return -1;
208 }
209
210 char *convert_path_a2u(const char *filename)
211 {
212         struct NameTranslationInfo nti;
213
214         if (!filename)
215         {
216                 return 0;
217         }
218
219         __translate_amiga_to_unix_path_name(&filename, &nti);
220
221         return mystrdup(filename);
222 }
223 char *convert_path_u2a(const char *filename)
224 {
225         struct NameTranslationInfo nti;
226
227         if (!filename)
228         {
229                 return 0;
230         }
231
232         if (strcmp(filename, "/dev/tty") == 0)
233         {
234                 return mystrdup("CONSOLE:");
235                 ;
236         }
237
238         __translate_unix_to_amiga_path_name(&filename, &nti);
239
240         return mystrdup(filename);
241 }
242
243 static struct SignalSemaphore environ_sema;
244
245 void amigaos4_init_environ_sema()
246 {
247         IExec->InitSemaphore(&environ_sema);
248 }
249
250 void amigaos4_obtain_environ()
251 {
252         IExec->ObtainSemaphore(&environ_sema);
253 }
254
255 void amigaos4_release_environ()
256 {
257         IExec->ReleaseSemaphore(&environ_sema);
258 }
259
260 static void createvars(char **envp)
261 {
262         if (envp)
263         {
264                 /* Set a local var to indicate to any subsequent sh that it is
265                 * not
266                 * the top level shell and so should only inherit local amigaos
267                 * vars */
268                 IDOS->SetVar("ABCSH_IMPORT_LOCAL", "TRUE", 5, GVF_LOCAL_ONLY);
269
270                 amigaos4_obtain_environ();
271
272                 envp = myenviron;
273
274                 while ((envp != NULL) && (*envp != NULL))
275                 {
276                         int len;
277                         char *var;
278                         char *val;
279                         if ((len = strlen(*envp)))
280                         {
281                                 if ((var = (char *)IExec->AllocVecTags(len + 1, AVT_ClearWithValue,0,TAG_DONE)))
282                                 {
283                                         strcpy(var, *envp);
284
285                                         val = strchr(var, '=');
286                                         if (val)
287                                         {
288                                                 *val++ = '\0';
289                                                 if (*val)
290                                                 {
291                                                         IDOS->SetVar(
292                                                             var, val,
293                                                             strlen(val) + 1,
294                                                             GVF_LOCAL_ONLY);
295                                                 }
296                                         }
297                                         IExec->FreeVec(var);
298                                 }
299                         }
300                         envp++;
301                 }
302                 amigaos4_release_environ();
303         }
304 }
305
306 struct command_data
307 {
308         STRPTR args;
309         BPTR seglist;
310         struct Task *parent;
311 };
312
313 int myexecvp(bool isperlthread, const char *filename, char *argv[])
314 {
315         //      adebug("%s %ld
316         //%s\n",__FUNCTION__,__LINE__,filename?filename:"NULL");
317         /* if there's a slash or a colon consider filename a path and skip
318          * search */
319         int res;
320         char *name = NULL;
321         char *pathpart = NULL;
322         if ((strchr(filename, '/') == NULL) && (strchr(filename, ':') == NULL))
323         {
324                 const char *path;
325                 const char *p;
326                 size_t len;
327                 struct stat st;
328
329                 if (!(path = getenv("PATH")))
330                 {
331                         path = ".:/bin:/usr/bin:/c";
332                 }
333
334                 len = strlen(filename) + 1;
335                 name = (char *)IExec->AllocVecTags(strlen(path) + len, AVT_ClearWithValue,0,AVT_Type,MEMF_SHARED,TAG_DONE);
336                 pathpart = (char *)IExec->AllocVecTags(strlen(path) + 1, AVT_ClearWithValue,0,AVT_Type,MEMF_SHARED,TAG_DONE);
337                 p = path;
338                 do
339                 {
340                         path = p;
341
342                         if (!(p = strchr(path, ':')))
343                         {
344                                 p = strchr(path, '\0');
345                         }
346
347                         memcpy(pathpart, path, p - path);
348                         pathpart[p - path] = '\0';
349                         if (!(strlen(pathpart) == 0))
350                         {
351                                 sprintf(name, "%s/%s", pathpart, filename);
352                         }
353                         else
354                                 sprintf(name, "%s", filename);
355
356                         if ((stat(name, &st) == 0) && (S_ISREG(st.st_mode)))
357                         {
358                                 /* we stated it and it's a regular file */
359                                 /* let's boogie! */
360                                 filename = name;
361                                 break;
362                         }
363
364                 }
365                 while (*p++ != '\0');
366         }
367
368         res = myexecve(isperlthread, filename, argv, myenviron);
369
370         if(name)
371         {
372                 IExec->FreeVec((APTR)name);
373                 name = NULL;
374         }
375         if(pathpart)
376         {
377                 IExec->FreeVec((APTR)pathpart);
378                 pathpart = NULL;
379         }
380         return res;
381 }
382
383 int myexecv(bool isperlthread, const char *path, char *argv[])
384 {
385         return myexecve(isperlthread, path, argv, myenviron);
386 }
387
388 int myexecl(bool isperlthread, const char *path, ...)
389 {
390         va_list va;
391         char *argv[1024]; /* 1024 enough? let's hope so! */
392         int i = 0;
393         // adebug("%s %ld\n",__FUNCTION__,__LINE__);
394
395         va_start(va, path);
396         i = 0;
397
398         do
399         {
400                 argv[i] = va_arg(va, char *);
401         }
402         while (argv[i++] != NULL);
403
404         va_end(va);
405         return myexecve(isperlthread, path, argv, myenviron);
406 }
407
408 int pause(void)
409 {
410         fprintf(stderr, "Pause not implemented\n");
411
412         errno = EINTR;
413         return -1;
414 }
415
416 uint32 size_env(struct Hook *hook, __attribute__((unused))APTR userdata, struct ScanVarsMsg *message)
417 {
418         if (strlen(message->sv_GDir) <= 4)
419         {
420                 hook->h_Data = (APTR)(((uint32)hook->h_Data) + 1);
421         }
422         return 0;
423 }
424
425 uint32 copy_env(struct Hook *hook, __attribute__((unused))APTR userdata, struct ScanVarsMsg *message)
426 {
427         if (strlen(message->sv_GDir) <= 4)
428         {
429                 char **env = (char **)hook->h_Data;
430                 uint32 size =
431                     strlen(message->sv_Name) + 1 + message->sv_VarLen + 1 + 1;
432                 char *buffer = (char *)IExec->AllocVecTags((uint32)size,AVT_ClearWithValue,0,TAG_DONE);
433
434
435                 snprintf(buffer, size - 1, "%s=%s", message->sv_Name,
436                          message->sv_Var);
437
438                 *env = buffer;
439                 env++;
440                 hook->h_Data = env;
441         }
442         return 0;
443 }
444
445 void ___makeenviron()
446 {
447         struct Hook *hook = (struct Hook *)IExec->AllocSysObjectTags(ASOT_HOOK,TAG_DONE);
448
449         if(hook)
450         {
451                 char varbuf[8];
452                 uint32 flags = 0;
453
454                 struct DOSIFace *myIDOS =
455                     (struct DOSIFace *)OpenInterface("dos.library", 53);
456                 if (myIDOS)
457                 {
458                         uint32 size = 0;
459                         if (myIDOS->GetVar("ABCSH_IMPORT_LOCAL", varbuf, 8,
460                                            GVF_LOCAL_ONLY) > 0)
461                         {
462                                 flags = GVF_LOCAL_ONLY;
463                         }
464                         else
465                         {
466                                 flags = GVF_GLOBAL_ONLY;
467                         }
468
469                         hook->h_Entry = size_env;
470                         hook->h_Data = 0;
471
472                         myIDOS->ScanVars(hook, flags, 0);
473                         size  = ((uint32)hook->h_Data) + 1;
474
475                         myenviron = (char **)IExec->AllocVecTags(size *
476                                     sizeof(char **),
477                                     AVT_ClearWithValue,0,TAG_DONE);
478                         origenviron = myenviron;
479                         if (!myenviron)
480                         {
481                                 IExec->FreeSysObject(ASOT_HOOK,hook);
482                                 CloseInterface((struct Interface *)myIDOS);
483                                 return;
484                         }
485                         hook->h_Entry = copy_env;
486                         hook->h_Data = myenviron;
487
488                         myIDOS->ScanVars(hook, flags, 0);
489                         IExec->FreeSysObject(ASOT_HOOK,hook);
490                         CloseInterface((struct Interface *)myIDOS);
491                 }
492         }
493 }
494
495 void ___freeenviron()
496 {
497         char **i;
498         /* perl might change environ, it puts it back except for ctrl-c */
499         /* so restore our own copy here */
500         struct DOSIFace *myIDOS =
501             (struct DOSIFace *)OpenInterface("dos.library", 53);
502         if (myIDOS)
503         {
504                 myenviron = origenviron;
505
506                 if (myenviron)
507                 {
508                         for (i = myenviron; *i != NULL; i++)
509                         {
510                                 IExec->FreeVec(*i);
511                         }
512                         IExec->FreeVec(myenviron);
513                         myenviron = NULL;
514                 }
515                 CloseInterface((struct Interface *)myIDOS);
516         }
517 }
518
519 /* reimplementation of popen, clib2's doesn't do all we want */
520
521 int popen_child()
522 {
523         struct Task *thisTask = IExec->FindTask(0);
524
525         char *command = (char *)thisTask->tc_UserData;
526         const char *argv[4];
527
528         argv[0] = "sh";
529         argv[1] = "-c";
530         argv[2] = command ? command : NULL;
531         argv[3] = NULL;
532
533         // adebug("%s %ld  %s\n",__FUNCTION__,__LINE__,command?command:"NULL");
534
535         /* We need to give this to sh via execvp, execvp expects filename,
536          * argv[]
537          */
538
539         myexecvp(FALSE, argv[0], (char **)argv);
540         if (command)
541                 IExec->FreeVec(command);
542
543         IExec->Forbid();
544         return 0;
545 }
546
547
548 FILE *amigaos_popen(const char *cmd, const char *mode)
549 {
550         FILE *result = NULL;
551         char pipe_name[50];
552         char unix_pipe[50];
553         char ami_pipe[50];
554         char *cmd_copy;
555         BPTR input = 0;
556         BPTR output = 0;
557         struct Process *proc = NULL;
558         struct Task *thisTask = IExec->FindTask(0);
559
560         /* First we need to check the mode
561          * We can only have unidirectional pipes
562          */
563         //    adebug("%s %ld cmd %s mode %s \n",__FUNCTION__,__LINE__,cmd,
564         //    mode);
565
566         switch (mode[0])
567         {
568         case 'r':
569         case 'w':
570                 break;
571
572         default:
573
574                 errno = EINVAL;
575                 return result;
576         }
577
578         /* Make a unique pipe name
579          * we need a unix one and an amigaos version (of the same pipe!)
580          * as were linking with libunix.
581          */
582
583         sprintf(pipe_name, "%x%08lx/4096/0", pipenum++,
584                 IUtility->GetUniqueID());
585         sprintf(unix_pipe, "/PIPE/%s", pipe_name);
586         sprintf(ami_pipe, "PIPE:%s", pipe_name);
587
588         /* Now we open the AmigaOs filehandles that we will pass to our
589          * subprocess
590          */
591
592         if (mode[0] == 'r')
593         {
594                 /* A read mode pipe: Output from pipe input from Output() or NIL:*/
595                 /* First attempt to DUP Output() */
596                 input = IDOS->DupFileHandle(IDOS->Output());
597                 if(input == 0)
598                 {
599                         input = IDOS->Open("NIL:", MODE_READWRITE);
600                 }
601                 if (input != 0)
602                 {
603                         output = IDOS->Open(ami_pipe, MODE_NEWFILE);
604                 }
605                 result = fopen(unix_pipe, mode);
606         }
607         else
608         {
609                 /* Open the write end first! */
610
611                 result = fopen(unix_pipe, mode);
612
613                 input = IDOS->Open(ami_pipe, MODE_OLDFILE);
614                 if (input != 0)
615                 {
616                         output = IDOS->DupFileHandle(IDOS->Input());
617                         if(output == 0)
618                         {
619                                 output = IDOS->Open("NIL:", MODE_READWRITE);
620                         }
621                 }
622         }
623         if ((input == 0) || (output == 0) || (result == NULL))
624         {
625                 /* Ouch stream opening failed */
626                 /* Close and bail */
627                 if (input)
628                         IDOS->Close(input);
629                 if (output)
630                         IDOS->Close(output);
631                 if(result)
632                 {
633                         fclose(result);
634                         result = NULL;
635                 }
636                 return result;
637         }
638
639         /* We have our streams now start our new process
640          * We're using a new process so that execve can modify the environment
641          * with messing things up for the shell that launched perl
642          * Copy cmd before we launch the subprocess as perl seems to waste
643          * no time in overwriting it! The subprocess will free the copy.
644          */
645
646         if ((cmd_copy = mystrdup(cmd)))
647         {
648                 // adebug("%s %ld
649                 // %s\n",__FUNCTION__,__LINE__,cmd_copy?cmd_copy:"NULL");
650                 proc = IDOS->CreateNewProcTags(
651                            NP_Entry, popen_child, NP_Child, TRUE, NP_StackSize,
652                            ((struct Process *)thisTask)->pr_StackSize, NP_Input, input,
653                            NP_Output, output, NP_Error, IDOS->ErrorOutput(),
654                            NP_CloseError, FALSE, NP_Cli, TRUE, NP_Name,
655                            "Perl: popen process", NP_UserData, (int)cmd_copy,
656                            TAG_DONE);
657         }
658         if (!proc)
659         {
660                 /* New Process Failed to start
661                  * Close and bail out
662                  */
663                 if (input)
664                         IDOS->Close(input);
665                 if (output)
666                         IDOS->Close(output);
667                 if (cmd_copy)
668                         IExec->FreeVec(cmd_copy);
669                 if(result)
670                 {
671                         fclose(result);
672                         result = NULL;
673                 }
674         }
675
676         /* Our new process is running and will close it streams etc
677          * once its done. All we need to is open the pipe via stdio
678          */
679
680         return result;
681 }
682
683 /* Workaround for clib2 fstat */
684 #ifndef S_IFCHR
685 #define S_IFCHR 0x0020000
686 #endif
687
688 #define SET_FLAG(u, v) ((void)((u) |= (v)))
689
690 int afstat(int fd, struct stat *statb)
691 {
692         int result;
693         BPTR fh;
694         int mode;
695         BOOL input;
696         /* In the first instance pass it to fstat */
697         // adebug("fd %ld ad %ld\n",fd,amigaos_get_file(fd));
698
699         if ((result = fstat(fd, statb) >= 0))
700                 return result;
701
702         /* Now we've got a file descriptor but we failed to stat it */
703         /* Could be a nil: or could be a std#? */
704
705         /* if get_default_file fails we had a dud fd so return failure */
706 #if !defined(__CLIB2__)
707
708         fh = amigaos_get_file(fd);
709
710         /* if nil: return failure*/
711         if (fh == 0)
712                 return -1;
713
714         /* Now compare with our process Input() Output() etc */
715         /* if these were regular files sockets or pipes we had already
716          * succeeded */
717         /* so we can guess they a character special console.... I hope */
718
719         struct ExamineData *data;
720         char name[120];
721         name[0] = '\0';
722
723         data = IDOS->ExamineObjectTags(EX_FileHandleInput, fh, TAG_END);
724         if (data != NULL)
725         {
726
727                 IUtility->Strlcpy(name, data->Name, sizeof(name));
728
729                 IDOS->FreeDosObject(DOS_EXAMINEDATA, data);
730         }
731
732         // adebug("ad %ld '%s'\n",amigaos_get_file(fd),name);
733         mode = S_IFCHR;
734
735         if (fh == IDOS->Input())
736         {
737                 input = TRUE;
738                 SET_FLAG(mode, S_IRUSR);
739                 SET_FLAG(mode, S_IRGRP);
740                 SET_FLAG(mode, S_IROTH);
741         }
742         else if (fh == IDOS->Output() || fh == IDOS->ErrorOutput())
743         {
744                 input = FALSE;
745                 SET_FLAG(mode, S_IWUSR);
746                 SET_FLAG(mode, S_IWGRP);
747                 SET_FLAG(mode, S_IWOTH);
748         }
749         else
750         {
751                 /* we got a filehandle not handle by fstat or the above */
752                 /* most likely it's NIL: but lets check */
753                 struct ExamineData *exd = NULL;
754                 if ((exd = IDOS->ExamineObjectTags(EX_FileHandleInput, fh,
755                                                    TAG_DONE)))
756                 {
757                         BOOL isnil = FALSE;
758                         if (exd->Type ==
759                                 (20060920)) // Ugh yes I know nasty.....
760                         {
761                                 isnil = TRUE;
762                         }
763                         IDOS->FreeDosObject(DOS_EXAMINEDATA, exd);
764                         if (isnil)
765                         {
766                                 /* yep we got NIL: */
767                                 SET_FLAG(mode, S_IRUSR);
768                                 SET_FLAG(mode, S_IRGRP);
769                                 SET_FLAG(mode, S_IROTH);
770                                 SET_FLAG(mode, S_IWUSR);
771                                 SET_FLAG(mode, S_IWGRP);
772                                 SET_FLAG(mode, S_IWOTH);
773                         }
774                         else
775                         {
776                                 IExec->DebugPrintF(
777                                     "unhandled filehandle in afstat()\n");
778                                 return -1;
779                         }
780                 }
781         }
782
783         memset(statb, 0, sizeof(statb));
784
785         statb->st_mode = mode;
786
787 #endif
788         return 0;
789 }
790
791 BPTR amigaos_get_file(int fd)
792 {
793         BPTR fh = (BPTR)NULL;
794         if (!(fh = _get_osfhandle(fd)))
795         {
796                 switch (fd)
797                 {
798                 case 0:
799                         fh = IDOS->Input();
800                         break;
801                 case 1:
802                         fh = IDOS->Output();
803                         break;
804                 case 2:
805                         fh = IDOS->ErrorOutput();
806                         break;
807                 default:
808                         break;
809                 }
810         }
811         return fh;
812 }
813
814 /*########################################################################*/
815
816 #define LOCK_START 0xFFFFFFFFFFFFFFFELL
817 #define LOCK_LENGTH 1LL
818
819 // No wait forever option so lets wait for a loooong time.
820 #define TIMEOUT 0x7FFFFFFF
821
822 int amigaos_flock(int fd, int oper)
823 {
824         BPTR fh;
825         int32 success = -1;
826
827         if (!(fh = amigaos_get_file(fd)))
828         {
829                 errno = EBADF;
830                 return -1;
831         }
832
833         switch (oper)
834         {
835         case LOCK_SH:
836         {
837                 if (IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
838                                      REC_SHARED | RECF_DOS_METHOD_ONLY,
839                                      TIMEOUT))
840                 {
841                         success = 0;
842                 }
843                 break;
844         }
845         case LOCK_EX:
846         {
847                 if (IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
848                                      REC_EXCLUSIVE | RECF_DOS_METHOD_ONLY,
849                                      TIMEOUT))
850                 {
851                         success = 0;
852                 }
853                 break;
854         }
855         case LOCK_SH | LOCK_NB:
856         {
857                 if (IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
858                                      REC_SHARED_IMMED | RECF_DOS_METHOD_ONLY,
859                                      TIMEOUT))
860                 {
861                         success = 0;
862                 }
863                 else
864                 {
865                         errno = EWOULDBLOCK;
866                 }
867                 break;
868         }
869         case LOCK_EX | LOCK_NB:
870         {
871                 if (IDOS->LockRecord(fh, LOCK_START, LOCK_LENGTH,
872                                      REC_EXCLUSIVE_IMMED | RECF_DOS_METHOD_ONLY,
873                                      TIMEOUT))
874                 {
875                         success = 0;
876                 }
877                 else
878                 {
879                         errno = EWOULDBLOCK;
880                 }
881                 break;
882         }
883         case LOCK_UN:
884         {
885                 if (IDOS->UnLockRecord(fh, LOCK_START, LOCK_LENGTH))
886                 {
887                         success = 0;
888                 }
889                 break;
890         }
891         default:
892         {
893                 errno = EINVAL;
894                 return -1;
895         }
896         }
897         return success;
898 }