@@ -423,6 +423,30 @@ fcntl_flock_impl(PyObject *module, int fd, int code)
423423}
424424
425425
426+ static void
427+ fill_struct_flock (struct flock * l , PyObject * lenobj , PyObject * startobj )
428+ {
429+ l -> l_start = l -> l_len = 0 ;
430+ if (startobj != NULL ) {
431+ #if !defined(HAVE_LARGEFILE_SUPPORT )
432+ l -> l_start = PyLong_AsLong (startobj );
433+ #else
434+ l -> l_start = PyLong_Check (startobj ) ?
435+ PyLong_AsLongLong (startobj ) :
436+ PyLong_AsLong (startobj );
437+ #endif
438+ }
439+ if (lenobj != NULL ) {
440+ #if !defined(HAVE_LARGEFILE_SUPPORT )
441+ l -> l_len = PyLong_AsLong (lenobj );
442+ #else
443+ l -> l_len = PyLong_Check (lenobj ) ?
444+ PyLong_AsLongLong (lenobj ) :
445+ PyLong_AsLong (lenobj );
446+ #endif
447+ }
448+ }
449+
426450/*[clinic input]
427451fcntl.lockf
428452
@@ -489,29 +513,9 @@ fcntl_lockf_impl(PyObject *module, int fd, int code, PyObject *lenobj,
489513 "unrecognized lockf argument" );
490514 return NULL ;
491515 }
492- l .l_start = l .l_len = 0 ;
493- if (startobj != NULL ) {
494- #if !defined(HAVE_LARGEFILE_SUPPORT )
495- l .l_start = PyLong_AsLong (startobj );
496- #else
497- l .l_start = PyLong_Check (startobj ) ?
498- PyLong_AsLongLong (startobj ) :
499- PyLong_AsLong (startobj );
500- #endif
501- if (PyErr_Occurred ())
502- return NULL ;
503- }
504- if (lenobj != NULL ) {
505- #if !defined(HAVE_LARGEFILE_SUPPORT )
506- l .l_len = PyLong_AsLong (lenobj );
507- #else
508- l .l_len = PyLong_Check (lenobj ) ?
509- PyLong_AsLongLong (lenobj ) :
510- PyLong_AsLong (lenobj );
511- #endif
512- if (PyErr_Occurred ())
513- return NULL ;
514- }
516+ fill_struct_flock (& l , lenobj , startobj );
517+ if (PyErr_Occurred ())
518+ return NULL ;
515519 l .l_whence = whence ;
516520 do {
517521 Py_BEGIN_ALLOW_THREADS
@@ -525,13 +529,107 @@ fcntl_lockf_impl(PyObject *module, int fd, int code, PyObject *lenobj,
525529 Py_RETURN_NONE ;
526530}
527531
532+
533+ /*[clinic input]
534+ fcntl.getlk
535+
536+ fd: fildes
537+ cmd as code: int
538+ len as lenobj: object(c_default='NULL') = 0
539+ start as startobj: object(c_default='NULL') = 0
540+ whence: int = 0
541+ /
542+
543+ A wrapper around the fcntl(F_GETLK) locking call.
544+
545+ `fd` is the file descriptor of the file whose lock status to get. `cmd`
546+ is one of the following values:
547+
548+ LOCK_SH - check for conflicting exclusive lock
549+ LOCK_EX - check for conflicting shared or exclusive lock
550+
551+ Note that the returned information identifies a lock that would conflict
552+ with acquiring the type of lock specified in `cmd`. Calling with
553+ LOCK_SH therefore only returns information on a conflicting LOCK_EX,
554+ while calling with LOCK_EX returns information on either LOCK_SH or
555+ LOCK_EX locks.
556+
557+ The remaining parameters are as with `lockf`.
558+
559+ Returns a tuple of (pid, cmd, len, start, whence) if a conflicting
560+ lock is found. If more than one lock conflicts, platform code chooses
561+ one. There may not be an associated process, in which case pid will
562+ be -1.
563+
564+ If no other lock would conflict with the request, this function returns
565+ None.
566+
567+ The information returned by this call may already be outdated by the
568+ time it returns. Additionally, only locks acquired using `lockf` (or
569+ `fcntl(F_SETLK)`) are considered by this call.
570+ [clinic start generated code]*/
571+
572+ static PyObject *
573+ fcntl_getlk_impl (PyObject * module , int fd , int code , PyObject * lenobj ,
574+ PyObject * startobj , int whence )
575+ /*[clinic end generated code: output=2a7ba40514c0f66b input=6c2227b45838a146]*/
576+ {
577+ int ret ;
578+ int async_err = 0 ;
579+ struct flock l ;
580+
581+ if (PySys_Audit ("fcntl.getlk" , "iiOOi" , fd , code , lenobj ? lenobj : Py_None ,
582+ startobj ? startobj : Py_None , whence ) < 0 ) {
583+ return NULL ;
584+ }
585+
586+ /* LOCK_UN and combinations make no sense for F_GETLK */
587+ if (code == LOCK_SH )
588+ l .l_type = F_RDLCK ;
589+ else if (code == LOCK_EX )
590+ l .l_type = F_WRLCK ;
591+ else {
592+ PyErr_SetString (PyExc_ValueError ,
593+ "unrecognized getlk argument" );
594+ return NULL ;
595+ }
596+ fill_struct_flock (& l , lenobj , startobj );
597+ if (PyErr_Occurred ())
598+ return NULL ;
599+ l .l_whence = whence ;
600+ do {
601+ Py_BEGIN_ALLOW_THREADS
602+ ret = fcntl (fd , F_GETLK , & l );
603+ Py_END_ALLOW_THREADS
604+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
605+
606+ if (ret < 0 ) {
607+ return !async_err ? PyErr_SetFromErrno (PyExc_OSError ) : NULL ;
608+ } else {
609+ int cmd = 0 ;
610+
611+ if (l .l_type == F_UNLCK )
612+ Py_RETURN_NONE ;
613+ else if (l .l_type == F_RDLCK )
614+ cmd = LOCK_SH ;
615+ else if (l .l_type == F_WRLCK )
616+ cmd = LOCK_EX ;
617+
618+ /* casts necessary since types in OS header are unknown */
619+ return Py_BuildValue ("LiLLi" , (long long )l .l_pid , cmd ,
620+ (long long )l .l_len , (long long )l .l_start ,
621+ (int )l .l_whence );
622+ }
623+ }
624+
528625/* List of functions */
529626
530627static PyMethodDef fcntl_methods [] = {
531628 FCNTL_FCNTL_METHODDEF
532629 FCNTL_IOCTL_METHODDEF
533630 FCNTL_FLOCK_METHODDEF
534631 FCNTL_LOCKF_METHODDEF
632+ FCNTL_GETLK_METHODDEF
535633 {NULL , NULL } /* sentinel */
536634};
537635
0 commit comments