// Code generated by modernc.org/undup from the per-target sqlite_*.go files; DO NOT EDIT.

//go:build (freebsd && arm64) || (linux && arm64) || (linux && ppc64le) || (linux && riscv64) || (linux && s390x)

package sqlite3

import (
	"unsafe"

	"modernc.org/libc"
)

// C documentation
//
//	/*
//	** This function is called to obtain a shared lock on the database file.
//	** It is illegal to call sqlite3PagerGet() until after this function
//	** has been successfully called. If a shared-lock is already held when
//	** this function is called, it is a no-op.
//	**
//	** The following operations are also performed by this function.
//	**
//	**   1) If the pager is currently in PAGER_OPEN state (no lock held
//	**      on the database file), then an attempt is made to obtain a
//	**      SHARED lock on the database file. Immediately after obtaining
//	**      the SHARED lock, the file-system is checked for a hot-journal,
//	**      which is played back if present. Following any hot-journal
//	**      rollback, the contents of the cache are validated by checking
//	**      the 'change-counter' field of the database file header and
//	**      discarded if they are found to be invalid.
//	**
//	**   2) If the pager is running in exclusive-mode, and there are currently
//	**      no outstanding references to any pages, and is in the error state,
//	**      then an attempt is made to clear the error state by discarding
//	**      the contents of the page cache and rolling back any open journal
//	**      file.
//	**
//	** If everything is successful, SQLITE_OK is returned. If an IO error
//	** occurs while locking the database, checking for a hot-journal file or
//	** rolling back a journal file, the IO error code is returned.
//	*/
func _sqlite3PagerSharedLock(tls *libc.TLS, pPager uintptr) (r int32) {
	bp := tls.Alloc(32)
	defer tls.Free(32)
	var f, rc int32
	var pVfs uintptr
	var _ /* bExists at bp+4 */ int32
	var _ /* bHotJournal at bp+0 */ int32
	var _ /* dbFileVers at bp+12 */ [16]uint8
	var _ /* fout at bp+8 */ int32
	_, _, _ = f, pVfs, rc
	rc = SQLITE_OK /* Return code */
	/* This routine is only called from b-tree and only when there are no
	 ** outstanding pages. This implies that the pager state should either
	 ** be OPEN or READER. READER is only possible if the pager is or was in
	 ** exclusive access mode.  */
	if !((*TPager)(unsafe.Pointer(pPager)).FpWal != libc.UintptrFromInt32(0)) && libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == PAGER_OPEN {
		**(**int32)(__ccgo_up(bp)) = int32(1) /* True if there exists a hot journal-file */
		rc = _pager_wait_on_lock(tls, pPager, int32(SHARED_LOCK))
		if rc != SQLITE_OK {
			goto failed
		}
		/* If a journal file exists, and there is no RESERVED lock on the
		 ** database file, then it either needs to be played back or deleted.
		 */
		if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeLock) <= int32(SHARED_LOCK) {
			rc = _hasHotJournal(tls, pPager, bp)
		}
		if rc != SQLITE_OK {
			goto failed
		}
		if **(**int32)(__ccgo_up(bp)) != 0 {
			if (*TPager)(unsafe.Pointer(pPager)).FreadOnly != 0 {
				rc = libc.Int32FromInt32(SQLITE_READONLY) | libc.Int32FromInt32(3)<<libc.Int32FromInt32(8)
				goto failed
			}
			/* Get an EXCLUSIVE lock on the database file. At this point it is
			 ** important that a RESERVED lock is not obtained on the way to the
			 ** EXCLUSIVE lock. If it were, another process might open the
			 ** database file, detect the RESERVED lock, and conclude that the
			 ** database is safe to read while this process is still rolling the
			 ** hot-journal back.
			 **
			 ** Because the intermediate RESERVED lock is not requested, any
			 ** other process attempting to access the database file will get to
			 ** this point in the code and fail to obtain its own EXCLUSIVE lock
			 ** on the database file.
			 **
			 ** Unless the pager is in locking_mode=exclusive mode, the lock is
			 ** downgraded to SHARED_LOCK before this function returns.
			 */
			rc = _pagerLockDb(tls, pPager, int32(EXCLUSIVE_LOCK))
			if rc != SQLITE_OK {
				goto failed
			}
			/* If it is not already open and the file exists on disk, open the
			 ** journal for read/write access. Write access is required because
			 ** in exclusive-access mode the file descriptor will be kept open
			 ** and possibly used for a transaction later on. Also, write-access
			 ** is usually required to finalize the journal in journal_mode=persist
			 ** mode (and also for journal_mode=truncate on some systems).
			 **
			 ** If the journal does not exist, it usually means that some
			 ** other connection managed to get in and roll it back before
			 ** this connection obtained the exclusive lock above. Or, it
			 ** may mean that the pager was in the error-state when this
			 ** function was called and the journal file does not exist.
			 */
			if !((*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != libc.UintptrFromInt32(0)) && libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FjournalMode) != int32(PAGER_JOURNALMODE_OFF) {
				pVfs = (*TPager)(unsafe.Pointer(pPager)).FpVfs /* True if journal file exists */
				rc = _sqlite3OsAccess(tls, pVfs, (*TPager)(unsafe.Pointer(pPager)).FzJournal, SQLITE_ACCESS_EXISTS, bp+4)
				if rc == SQLITE_OK && **(**int32)(__ccgo_up(bp + 4)) != 0 {
					**(**int32)(__ccgo_up(bp + 8)) = 0
					f = libc.Int32FromInt32(SQLITE_OPEN_READWRITE) | libc.Int32FromInt32(SQLITE_OPEN_MAIN_JOURNAL)
					rc = _sqlite3OsOpen(tls, pVfs, (*TPager)(unsafe.Pointer(pPager)).FzJournal, (*TPager)(unsafe.Pointer(pPager)).Fjfd, f, bp+8)
					if rc == SQLITE_OK && **(**int32)(__ccgo_up(bp + 8))&int32(SQLITE_OPEN_READONLY) != 0 {
						rc = _sqlite3CantopenError(tls, int32(64944))
						_sqlite3OsClose(tls, (*TPager)(unsafe.Pointer(pPager)).Fjfd)
					}
				}
			}
			/* Playback and delete the journal.  Drop the database write
			 ** lock and reacquire the read lock. Purge the cache before
			 ** playing back the hot-journal so that we don't end up with
			 ** an inconsistent cache.  Sync the hot journal before playing
			 ** it back since the process that crashed and left the hot journal
			 ** probably did not sync it and we are required to always sync
			 ** the journal before playing it back.
			 */
			if (*Tsqlite3_file)(unsafe.Pointer((*TPager)(unsafe.Pointer(pPager)).Fjfd)).FpMethods != uintptr(0) {
				rc = _pagerSyncHotJournal(tls, pPager)
				if rc == SQLITE_OK {
					rc = _pager_playback(tls, pPager, libc.BoolInt32(!((*TPager)(unsafe.Pointer(pPager)).FtempFile != 0)))
					(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_OPEN)
				}
			} else {
				if !((*TPager)(unsafe.Pointer(pPager)).FexclusiveMode != 0) {
					_pagerUnlockDb(tls, pPager, int32(SHARED_LOCK))
				}
			}
			if rc != SQLITE_OK {
				/* This branch is taken if an error occurs while trying to open
				 ** or roll back a hot-journal while holding an EXCLUSIVE lock. The
				 ** pager_unlock() routine will be called before returning to unlock
				 ** the file. If the unlock attempt fails, then Pager.eLock must be
				 ** set to UNKNOWN_LOCK (see the comment above the #define for
				 ** UNKNOWN_LOCK above for an explanation).
				 **
				 ** In order to get pager_unlock() to do this, set Pager.eState to
				 ** PAGER_ERROR now. This is not actually counted as a transition
				 ** to ERROR state in the state diagram at the top of this file,
				 ** since we know that the same call to pager_unlock() will very
				 ** shortly transition the pager object to the OPEN state. Calling
				 ** assert_pager_state() would fail now, as it should not be possible
				 ** to be in ERROR state when there are zero outstanding page
				 ** references.
				 */
				_pager_error(tls, pPager, rc)
				goto failed
			}
		}
		if !((*TPager)(unsafe.Pointer(pPager)).FtempFile != 0) && (*TPager)(unsafe.Pointer(pPager)).FhasHeldSharedLock != 0 {
			rc = _sqlite3OsRead(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, bp+12, int32(16), int64(24))
			if rc != SQLITE_OK {
				if rc != libc.Int32FromInt32(SQLITE_IOERR)|libc.Int32FromInt32(2)<<libc.Int32FromInt32(8) {
					goto failed
				}
				libc.Xmemset(tls, bp+12, 0, uint64(16))
			}
			if libc.Xmemcmp(tls, pPager+136, bp+12, uint64(16)) != 0 {
				_pager_reset(tls, pPager)
				/* Unmap the database file. It is possible that external processes
				 ** may have truncated the database file and then extended it back
				 ** to its original size while this process was not holding a lock.
				 ** In this case there may exist a Pager.pMap mapping that appears
				 ** to be the right size but is not actually valid. Avoid this
				 ** possibility by unmapping the db here. */
				if (*TPager)(unsafe.Pointer(pPager)).FbUseFetch != 0 {
					_sqlite3OsUnfetch(tls, (*TPager)(unsafe.Pointer(pPager)).Ffd, 0, uintptr(0))
				}
			}
		}
		/* If there is a WAL file in the file-system, open this database in WAL
		 ** mode. Otherwise, the following function call is a no-op.
		 */
		rc = _pagerOpenWalIfPresent(tls, pPager)
	}
	if (*TPager)(unsafe.Pointer(pPager)).FpWal != uintptr(0) {
		rc = _pagerBeginReadTransaction(tls, pPager)
	}
	if libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FtempFile) == 0 && libc.Int32FromUint8((*TPager)(unsafe.Pointer(pPager)).FeState) == PAGER_OPEN && rc == SQLITE_OK {
		rc = _pagerPagecount(tls, pPager, pPager+32)
	}
	goto failed
failed:
	;
	if rc != SQLITE_OK {
		_pager_unlock(tls, pPager)
	} else {
		(*TPager)(unsafe.Pointer(pPager)).FeState = uint8(PAGER_READER)
		(*TPager)(unsafe.Pointer(pPager)).FhasHeldSharedLock = uint8(1)
	}
	return rc
}
