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

//go:build (linux && amd64) || (linux && ppc64le) || (linux && s390x)

package sqlite3

import (
	"unsafe"

	"modernc.org/libc"
)

type Tblksize_t = int64

// C documentation
//
//	/*
//	** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
//	** file-control operation.  Enlarge the database to nBytes in size
//	** (rounded up to the next chunk-size).  If the database is already
//	** nBytes or larger, this routine is a no-op.
//	*/
func _fcntlSizeHint(tls *libc.TLS, pFile uintptr, nByte Ti64) (r int32) {
	bp := tls.Alloc(144)
	defer tls.Free(144)
	var iWrite, nSize Ti64
	var nBlk, nWrite, rc int32
	var _ /* buf at bp+0 */ Tstat
	_, _, _, _, _ = iWrite, nBlk, nSize, nWrite, rc
	if (*TunixFile)(unsafe.Pointer(pFile)).FszChunk > 0 { /* Used to hold return values of fstat() */
		if (*(*func(*libc.TLS, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(5)].FpCurrent})))(tls, (*TunixFile)(unsafe.Pointer(pFile)).Fh, bp) != 0 {
			return libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(7)<<libc.Int32FromInt32(8)
		}
		nSize = (nByte + int64((*TunixFile)(unsafe.Pointer(pFile)).FszChunk) - int64(1)) / int64((*TunixFile)(unsafe.Pointer(pFile)).FszChunk) * int64((*TunixFile)(unsafe.Pointer(pFile)).FszChunk)
		if nSize > int64((**(**Tstat)(__ccgo_up(bp))).Fst_size) {
			/* If the OS does not have posix_fallocate(), fake it. Write a
			 ** single byte to the last byte in each block that falls entirely
			 ** within the extended region. Then, if required, a single byte
			 ** at offset (nSize-1), to set the size of the file correctly.
			 ** This is a similar technique to that used by glibc on systems
			 ** that do not have a real fallocate() call.
			 */
			nBlk = int32((**(**Tstat)(__ccgo_up(bp))).Fst_blksize) /* File-system block size */
			nWrite = 0                                             /* Next offset to write to */
			iWrite = int64((**(**Tstat)(__ccgo_up(bp))).Fst_size/int64(nBlk)*int64(nBlk) + int64(nBlk) - int64(1))
			for {
				if !(iWrite < nSize+int64(nBlk)-int64(1)) {
					break
				}
				if iWrite >= nSize {
					iWrite = nSize - int64(1)
				}
				nWrite = _seekAndWrite(tls, pFile, iWrite, __ccgo_ts+1704, int32(1))
				if nWrite != int32(1) {
					return libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(3)<<libc.Int32FromInt32(8)
				}
				goto _1
			_1:
				;
				iWrite = iWrite + int64(nBlk)
			}
		}
	}
	if (*TunixFile)(unsafe.Pointer(pFile)).FmmapSizeMax > 0 && nByte > (*TunixFile)(unsafe.Pointer(pFile)).FmmapSize {
		if (*TunixFile)(unsafe.Pointer(pFile)).FszChunk <= 0 {
			if _robust_ftruncate(tls, (*TunixFile)(unsafe.Pointer(pFile)).Fh, nByte) != 0 {
				_storeLastErrno(tls, pFile, **(**int32)(__ccgo_up(libc.X__errno_location(tls))))
				return _unixLogErrorAtLine(tls, libc.Int32FromInt32(SQLITE_IOERR)|libc.Int32FromInt32(6)<<libc.Int32FromInt32(8), __ccgo_ts+3578, (*TunixFile)(unsafe.Pointer(pFile)).FzPath, int32(44297))
			}
		}
		rc = _unixMapfile(tls, pFile, nByte)
		return rc
	}
	return SQLITE_OK
}

// C documentation
//
//	/*
//	** Return TRUE if pFile has been renamed or unlinked since it was first opened.
//	*/
func _fileHasMoved(tls *libc.TLS, pFile uintptr) (r int32) {
	bp := tls.Alloc(144)
	defer tls.Free(144)
	var _ /* buf at bp+0 */ Tstat
	return libc.BoolInt32((*TunixFile)(unsafe.Pointer(pFile)).FpInode != uintptr(0) && ((*(*func(*libc.TLS, uintptr, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(4)].FpCurrent})))(tls, (*TunixFile)(unsafe.Pointer(pFile)).FzPath, bp) != 0 || uint64((**(**Tstat)(__ccgo_up(bp))).Fst_ino) != (*TunixInodeInfo)(unsafe.Pointer((*TunixFile)(unsafe.Pointer(pFile)).FpInode)).FfileId.Fino))
}

// C documentation
//
//	/*
//	** Given a file descriptor, locate the unixInodeInfo object that
//	** describes that file descriptor.  Create a new one if necessary.  The
//	** return value might be uninitialized if an error occurs.
//	**
//	** The global mutex must held when calling this routine.
//	**
//	** Return an appropriate error code.
//	*/
func _findInodeInfo(tls *libc.TLS, pFile uintptr, ppInode uintptr) (r int32) {
	bp := tls.Alloc(160)
	defer tls.Free(160)
	var fd, rc int32
	var pInode uintptr
	var _ /* fileId at bp+0 */ TunixFileId
	var _ /* statbuf at bp+16 */ Tstat
	_, _, _ = fd, pInode, rc /* Low-level file information */
	pInode = uintptr(0)      /* Candidate unixInodeInfo object */
	/* Get low-level information about the file that we can used to
	 ** create a unique name for the file.
	 */
	fd = (*TunixFile)(unsafe.Pointer(pFile)).Fh
	rc = (*(*func(*libc.TLS, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(5)].FpCurrent})))(tls, fd, bp+16)
	if rc != 0 {
		_storeLastErrno(tls, pFile, **(**int32)(__ccgo_up(libc.X__errno_location(tls))))
		return int32(SQLITE_IOERR)
	}
	libc.Xmemset(tls, bp, 0, uint64(16))
	(**(**TunixFileId)(__ccgo_up(bp))).Fdev = (**(**Tstat)(__ccgo_up(bp + 16))).Fst_dev
	(**(**TunixFileId)(__ccgo_up(bp))).Fino = uint64((**(**Tstat)(__ccgo_up(bp + 16))).Fst_ino)
	pInode = _inodeList
	for pInode != 0 && libc.Xmemcmp(tls, bp, pInode, uint64(16)) != 0 {
		pInode = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpNext
	}
	if pInode == uintptr(0) {
		pInode = Xsqlite3_malloc64(tls, uint64(80))
		if pInode == uintptr(0) {
			return int32(SQLITE_NOMEM)
		}
		libc.Xmemset(tls, pInode, 0, uint64(80))
		libc.Xmemcpy(tls, pInode, bp, uint64(16))
		if _sqlite3Config.FbCoreMutex != 0 {
			(*TunixInodeInfo)(unsafe.Pointer(pInode)).FpLockMutex = Xsqlite3_mutex_alloc(tls, SQLITE_MUTEX_FAST)
			if (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpLockMutex == uintptr(0) {
				Xsqlite3_free(tls, pInode)
				return int32(SQLITE_NOMEM)
			}
		}
		(*TunixInodeInfo)(unsafe.Pointer(pInode)).FnRef = int32(1)
		(*TunixInodeInfo)(unsafe.Pointer(pInode)).FpNext = _inodeList
		(*TunixInodeInfo)(unsafe.Pointer(pInode)).FpPrev = uintptr(0)
		if _inodeList != 0 {
			(*TunixInodeInfo)(unsafe.Pointer(_inodeList)).FpPrev = pInode
		}
		_inodeList = pInode
	} else {
		(*TunixInodeInfo)(unsafe.Pointer(pInode)).FnRef = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FnRef + 1
	}
	**(**uintptr)(__ccgo_up(ppInode)) = pInode
	return SQLITE_OK
}

// C documentation
//
//	/*
//	** Search for an unused file descriptor that was opened on the database
//	** file (not a journal or super-journal file) identified by pathname
//	** zPath with SQLITE_OPEN_XXX flags matching those passed as the second
//	** argument to this function.
//	**
//	** Such a file descriptor may exist if a database connection was closed
//	** but the associated file descriptor could not be closed because some
//	** other file descriptor open on the same file is holding a file-lock.
//	** Refer to comments in the unixClose() function and the lengthy comment
//	** describing "Posix Advisory Locking" at the start of this file for
//	** further details. Also, ticket #4018.
//	**
//	** If a suitable file descriptor is found, then it is returned. If no
//	** such file descriptor is located, -1 is returned.
//	*/
func _findReusableFd(tls *libc.TLS, zPath uintptr, flags int32) (r uintptr) {
	bp := tls.Alloc(144)
	defer tls.Free(144)
	var pInode, pUnused, pp uintptr
	var _ /* sStat at bp+0 */ Tstat
	_, _, _ = pInode, pUnused, pp
	pUnused = uintptr(0) /* Results of stat() call */
	_unixEnterMutex(tls)
	/* A stat() call may fail for various reasons. If this happens, it is
	 ** almost certain that an open() call on the same path will also fail.
	 ** For this reason, if an error occurs in the stat() call here, it is
	 ** ignored and -1 is returned. The caller will try to open a new file
	 ** descriptor on the same path, fail, and return an error to SQLite.
	 **
	 ** Even if a subsequent open() call does succeed, the consequences of
	 ** not searching for a reusable file descriptor are not dire.  */
	if _inodeList != uintptr(0) && 0 == (*(*func(*libc.TLS, uintptr, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(4)].FpCurrent})))(tls, zPath, bp) {
		pInode = _inodeList
		for pInode != 0 && ((*TunixInodeInfo)(unsafe.Pointer(pInode)).FfileId.Fdev != (**(**Tstat)(__ccgo_up(bp))).Fst_dev || (*TunixInodeInfo)(unsafe.Pointer(pInode)).FfileId.Fino != uint64((**(**Tstat)(__ccgo_up(bp))).Fst_ino)) {
			pInode = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpNext
		}
		if pInode != 0 {
			Xsqlite3_mutex_enter(tls, (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpLockMutex)
			flags = flags & (libc.Int32FromInt32(SQLITE_OPEN_READONLY) | libc.Int32FromInt32(SQLITE_OPEN_READWRITE))
			pp = pInode + 40
			for {
				if !(**(**uintptr)(__ccgo_up(pp)) != 0 && (*TUnixUnusedFd)(unsafe.Pointer(**(**uintptr)(__ccgo_up(pp)))).Fflags != flags) {
					break
				}
				goto _1
			_1:
				;
				pp = **(**uintptr)(__ccgo_up(pp)) + 8
			}
			pUnused = **(**uintptr)(__ccgo_up(pp))
			if pUnused != 0 {
				**(**uintptr)(__ccgo_up(pp)) = (*TUnixUnusedFd)(unsafe.Pointer(pUnused)).FpNext
			}
			Xsqlite3_mutex_leave(tls, (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpLockMutex)
		}
	}
	_unixLeaveMutex(tls)
	return pUnused
}

// C documentation
//
//	/*
//	** Determine the current size of a file in bytes
//	*/
func _unixFileSize(tls *libc.TLS, id uintptr, pSize uintptr) (r int32) {
	bp := tls.Alloc(144)
	defer tls.Free(144)
	var rc int32
	var _ /* buf at bp+0 */ Tstat
	_ = rc
	rc = (*(*func(*libc.TLS, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(5)].FpCurrent})))(tls, (*TunixFile)(unsafe.Pointer(id)).Fh, bp)
	if rc != 0 {
		_storeLastErrno(tls, id, **(**int32)(__ccgo_up(libc.X__errno_location(tls))))
		return libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(7)<<libc.Int32FromInt32(8)
	}
	**(**Ti64)(__ccgo_up(pSize)) = int64((**(**Tstat)(__ccgo_up(bp))).Fst_size)
	/* When opening a zero-size database, the findInodeInfo() procedure
	 ** writes a single byte into that file in order to work around a bug
	 ** in the OS-X msdos filesystem.  In order to avoid problems with upper
	 ** layers, we need to report this file size as zero even though it is
	 ** really 1.   Ticket #3260.
	 */
	if **(**Ti64)(__ccgo_up(pSize)) == int64(1) {
		**(**Ti64)(__ccgo_up(pSize)) = 0
	}
	return SQLITE_OK
}

// C documentation
//
//	/*
//	** Memory map or remap the file opened by file-descriptor pFd (if the file
//	** is already mapped, the existing mapping is replaced by the new). Or, if
//	** there already exists a mapping for this file, and there are still
//	** outstanding xFetch() references to it, this function is a no-op.
//	**
//	** If parameter nByte is non-negative, then it is the requested size of
//	** the mapping to create. Otherwise, if nByte is less than zero, then the
//	** requested size is the size of the file on disk. The actual size of the
//	** created mapping is either the requested size or the value configured
//	** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
//	**
//	** SQLITE_OK is returned if no error occurs (even if the mapping is not
//	** recreated as a result of outstanding references) or an SQLite error
//	** code otherwise.
//	*/
func _unixMapfile(tls *libc.TLS, pFd uintptr, nMap Ti64) (r int32) {
	bp := tls.Alloc(144)
	defer tls.Free(144)
	var _ /* statbuf at bp+0 */ Tstat
	if (*TunixFile)(unsafe.Pointer(pFd)).FnFetchOut > 0 {
		return SQLITE_OK
	}
	if nMap < 0 { /* Low-level file information */
		if (*(*func(*libc.TLS, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(5)].FpCurrent})))(tls, (*TunixFile)(unsafe.Pointer(pFd)).Fh, bp) != 0 {
			return libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(7)<<libc.Int32FromInt32(8)
		}
		nMap = int64((**(**Tstat)(__ccgo_up(bp))).Fst_size)
	}
	if nMap > (*TunixFile)(unsafe.Pointer(pFd)).FmmapSizeMax {
		nMap = (*TunixFile)(unsafe.Pointer(pFd)).FmmapSizeMax
	}
	if nMap != (*TunixFile)(unsafe.Pointer(pFd)).FmmapSize {
		_unixRemapfile(tls, pFd, nMap)
	}
	return SQLITE_OK
}

// C documentation
//
//	/*
//	** Open a shared-memory area associated with open database file pDbFd.
//	** This particular implementation uses mmapped files.
//	**
//	** The file used to implement shared-memory is in the same directory
//	** as the open database file and has the same name as the open database
//	** file with the "-shm" suffix added.  For example, if the database file
//	** is "/home/user1/config.db" then the file that is created and mmapped
//	** for shared memory will be called "/home/user1/config.db-shm".
//	**
//	** Another approach to is to use files in /dev/shm or /dev/tmp or an
//	** some other tmpfs mount. But if a file in a different directory
//	** from the database file is used, then differing access permissions
//	** or a chroot() might cause two different processes on the same
//	** database to end up using different files for shared memory -
//	** meaning that their memory would not really be shared - resulting
//	** in database corruption.  Nevertheless, this tmpfs file usage
//	** can be enabled at compile-time using -DSQLITE_SHM_DIRECTORY="/dev/shm"
//	** or the equivalent.  The use of the SQLITE_SHM_DIRECTORY compile-time
//	** option results in an incompatible build of SQLite;  builds of SQLite
//	** that with differing SQLITE_SHM_DIRECTORY settings attempt to use the
//	** same database file at the same time, database corruption will likely
//	** result. The SQLITE_SHM_DIRECTORY compile-time option is considered
//	** "unsupported" and may go away in a future SQLite release.
//	**
//	** When opening a new shared-memory file, if no other instances of that
//	** file are currently open, in this process or in other processes, then
//	** the file must be truncated to zero length or have its header cleared.
//	**
//	** If the original database file (pDbFd) is using the "unix-excl" VFS
//	** that means that an exclusive lock is held on the database file and
//	** that no other processes are able to read or write the database.  In
//	** that case, we do not really need shared memory.  No shared memory
//	** file is created.  The shared memory will be simulated with heap memory.
//	*/
func _unixOpenSharedMemory(tls *libc.TLS, pDbFd uintptr) (r int32) {
	bp := tls.Alloc(160)
	defer tls.Free(160)
	var nShmFilename, rc int32
	var p, pInode, pShmNode, zBasePath, zShm, v1 uintptr
	var _ /* sStat at bp+0 */ Tstat
	_, _, _, _, _, _, _, _ = nShmFilename, p, pInode, pShmNode, rc, zBasePath, zShm, v1
	p = uintptr(0) /* The underlying mmapped file */
	rc = SQLITE_OK /* Size of the SHM filename in bytes */
	/* Allocate space for the new unixShm object. */
	p = Xsqlite3_malloc64(tls, uint64(24))
	if p == uintptr(0) {
		return int32(SQLITE_NOMEM)
	}
	libc.Xmemset(tls, p, 0, uint64(24))
	/* Check to see if a unixShmNode object already exists. Reuse an existing
	 ** one if present. Create a new one if necessary.
	 */
	_unixEnterMutex(tls)
	pInode = (*TunixFile)(unsafe.Pointer(pDbFd)).FpInode
	pShmNode = (*TunixInodeInfo)(unsafe.Pointer(pInode)).FpShmNode
	if pShmNode == uintptr(0) { /* fstat() info for database file */
		zBasePath = (*TunixFile)(unsafe.Pointer(pDbFd)).FzPath
		/* Call fstat() to figure out the permissions on the database file. If
		 ** a new *-shm file is created, an attempt will be made to create it
		 ** with the same permissions.
		 */
		if (*(*func(*libc.TLS, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(5)].FpCurrent})))(tls, (*TunixFile)(unsafe.Pointer(pDbFd)).Fh, bp) != 0 {
			rc = libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(7)<<libc.Int32FromInt32(8)
			goto shm_open_err
		}
		nShmFilename = int32(6) + libc.Int32FromUint64(libc.Xstrlen(tls, zBasePath))
		pShmNode = Xsqlite3_malloc64(tls, uint64(uint64(96)+libc.Uint64FromInt32(nShmFilename)))
		if pShmNode == uintptr(0) {
			rc = int32(SQLITE_NOMEM)
			goto shm_open_err
		}
		libc.Xmemset(tls, pShmNode, 0, uint64(96)+libc.Uint64FromInt32(nShmFilename))
		v1 = pShmNode + 1*96
		(*TunixShmNode)(unsafe.Pointer(pShmNode)).FzFilename = v1
		zShm = v1
		Xsqlite3_snprintf(tls, nShmFilename, zShm, __ccgo_ts+3958, libc.VaList(bp+152, zBasePath))
		(*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm = -int32(1)
		(*TunixInodeInfo)(unsafe.Pointer((*TunixFile)(unsafe.Pointer(pDbFd)).FpInode)).FpShmNode = pShmNode
		(*TunixShmNode)(unsafe.Pointer(pShmNode)).FpInode = (*TunixFile)(unsafe.Pointer(pDbFd)).FpInode
		if _sqlite3Config.FbCoreMutex != 0 {
			(*TunixShmNode)(unsafe.Pointer(pShmNode)).FpShmMutex = Xsqlite3_mutex_alloc(tls, SQLITE_MUTEX_FAST)
			if (*TunixShmNode)(unsafe.Pointer(pShmNode)).FpShmMutex == uintptr(0) {
				rc = int32(SQLITE_NOMEM)
				goto shm_open_err
			}
		}
		if libc.Int32FromUint8((*TunixInodeInfo)(unsafe.Pointer(pInode)).FbProcessLock) == 0 {
			if 0 == Xsqlite3_uri_boolean(tls, (*TunixFile)(unsafe.Pointer(pDbFd)).FzPath, __ccgo_ts+3965, 0) {
				(*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm = _robust_open(tls, zShm, libc.Int32FromInt32(O_RDWR)|libc.Int32FromInt32(O_CREAT)|libc.Int32FromInt32(O_NOFOLLOW), (**(**Tstat)(__ccgo_up(bp))).Fst_mode&libc.Uint32FromInt32(0777))
			}
			if (*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm < 0 {
				(*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm = _robust_open(tls, zShm, libc.Int32FromInt32(O_RDONLY)|libc.Int32FromInt32(O_NOFOLLOW), (**(**Tstat)(__ccgo_up(bp))).Fst_mode&libc.Uint32FromInt32(0777))
				if (*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm < 0 {
					rc = _unixLogErrorAtLine(tls, _sqlite3CantopenError(tls, int32(45237)), __ccgo_ts+3542, zShm, int32(45237))
					goto shm_open_err
				}
				(*TunixShmNode)(unsafe.Pointer(pShmNode)).FisReadonly = uint8(1)
			}
			/* If this process is running as root, make sure that the SHM file
			 ** is owned by the same user that owns the original database.  Otherwise,
			 ** the original owner will not be able to connect.
			 */
			_robustFchown(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm, (**(**Tstat)(__ccgo_up(bp))).Fst_uid, (**(**Tstat)(__ccgo_up(bp))).Fst_gid)
			rc = _unixLockSharedMemory(tls, pDbFd, pShmNode)
			if rc != SQLITE_OK && rc != libc.Int32FromInt32(SQLITE_READONLY)|libc.Int32FromInt32(5)<<libc.Int32FromInt32(8) {
				goto shm_open_err
			}
		}
	}
	/* Make the new connection a child of the unixShmNode */
	(*TunixShm)(unsafe.Pointer(p)).FpShmNode = pShmNode
	(*TunixShmNode)(unsafe.Pointer(pShmNode)).FnRef = (*TunixShmNode)(unsafe.Pointer(pShmNode)).FnRef + 1
	(*TunixFile)(unsafe.Pointer(pDbFd)).FpShm = p
	_unixLeaveMutex(tls)
	/* The reference count on pShmNode has already been incremented under
	 ** the cover of the unixEnterMutex() mutex and the pointer from the
	 ** new (struct unixShm) object to the pShmNode has been set. All that is
	 ** left to do is to link the new object into the linked list starting
	 ** at pShmNode->pFirst. This must be done while holding the
	 ** pShmNode->pShmMutex.
	 */
	Xsqlite3_mutex_enter(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FpShmMutex)
	(*TunixShm)(unsafe.Pointer(p)).FpNext = (*TunixShmNode)(unsafe.Pointer(pShmNode)).FpFirst
	(*TunixShmNode)(unsafe.Pointer(pShmNode)).FpFirst = p
	Xsqlite3_mutex_leave(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FpShmMutex)
	return rc
	/* Jump here on any error */
	goto shm_open_err
shm_open_err:
	;
	_unixShmPurge(tls, pDbFd) /* This call frees pShmNode if required */
	Xsqlite3_free(tls, p)
	_unixLeaveMutex(tls)
	return rc
}

// C documentation
//
//	/*
//	** This function is called to obtain a pointer to region iRegion of the
//	** shared-memory associated with the database file fd. Shared-memory regions
//	** are numbered starting from zero. Each shared-memory region is szRegion
//	** bytes in size.
//	**
//	** If an error occurs, an error code is returned and *pp is set to NULL.
//	**
//	** Otherwise, if the bExtend parameter is 0 and the requested shared-memory
//	** region has not been allocated (by any client, including one running in a
//	** separate process), then *pp is set to NULL and SQLITE_OK returned. If
//	** bExtend is non-zero and the requested shared-memory region has not yet
//	** been allocated, it is allocated by this function.
//	**
//	** If the shared-memory region has already been allocated or is allocated by
//	** this call as described above, then it is mapped into this processes
//	** address space (if it is not already), *pp is set to point to the mapped
//	** memory and SQLITE_OK returned.
//	*/
func _unixShmMap(tls *libc.TLS, fd uintptr, iRegion int32, szRegion int32, bExtend int32, pp uintptr) (r int32) {
	bp := tls.Alloc(160)
	defer tls.Free(160)
	var apNew, p, pDbFd, pMem, pShmNode, zFile, v4 uintptr
	var i, iPg, nByte, nMap Ti64
	var nReqRegion, nShmPerMap, rc, v2 int32
	var _ /* sStat at bp+0 */ Tstat
	var _ /* x at bp+144 */ int32
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = apNew, i, iPg, nByte, nMap, nReqRegion, nShmPerMap, p, pDbFd, pMem, pShmNode, rc, zFile, v2, v4
	pDbFd = fd
	rc = SQLITE_OK
	nShmPerMap = _unixShmRegionPerMap(tls)
	/* If the shared-memory file has not yet been opened, open it now. */
	if (*TunixFile)(unsafe.Pointer(pDbFd)).FpShm == uintptr(0) {
		rc = _unixOpenSharedMemory(tls, pDbFd)
		if rc != SQLITE_OK {
			return rc
		}
	}
	p = (*TunixFile)(unsafe.Pointer(pDbFd)).FpShm
	pShmNode = (*TunixShm)(unsafe.Pointer(p)).FpShmNode
	Xsqlite3_mutex_enter(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FpShmMutex)
	if (*TunixShmNode)(unsafe.Pointer(pShmNode)).FisUnlocked != 0 {
		rc = _unixLockSharedMemory(tls, pDbFd, pShmNode)
		if rc != SQLITE_OK {
			goto shmpage_out
		}
		(*TunixShmNode)(unsafe.Pointer(pShmNode)).FisUnlocked = uint8(0)
	}
	/* Minimum number of regions required to be mapped. */
	nReqRegion = (iRegion + nShmPerMap) / nShmPerMap * nShmPerMap
	if libc.Int32FromUint16((*TunixShmNode)(unsafe.Pointer(pShmNode)).FnRegion) < nReqRegion { /* New apRegion[] array */
		nByte = int64(nReqRegion) * int64(szRegion) /* Used by fstat() */
		(*TunixShmNode)(unsafe.Pointer(pShmNode)).FszRegion = szRegion
		if (*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm >= 0 {
			/* The requested region is not mapped into this processes address space.
			 ** Check to see if it has been allocated (i.e. if the wal-index file is
			 ** large enough to contain the requested region).
			 */
			if (*(*func(*libc.TLS, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(5)].FpCurrent})))(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm, bp) != 0 {
				rc = libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(19)<<libc.Int32FromInt32(8)
				goto shmpage_out
			}
			if int64((**(**Tstat)(__ccgo_up(bp))).Fst_size) < nByte {
				/* The requested memory region does not exist. If bExtend is set to
				 ** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
				 */
				if !(bExtend != 0) {
					goto shmpage_out
				} else {
					/* Write to the last byte of each newly allocated or extended page */
					iPg = int64((**(**Tstat)(__ccgo_up(bp))).Fst_size / int64(_pgsz))
					for {
						if !(iPg < nByte/int64(_pgsz)) {
							break
						}
						**(**int32)(__ccgo_up(bp + 144)) = 0
						if _seekAndWriteFd(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm, iPg*int64(_pgsz)+int64(_pgsz)-int64(1), __ccgo_ts+1704, int32(1), bp+144) != int32(1) {
							zFile = (*TunixShmNode)(unsafe.Pointer(pShmNode)).FzFilename
							rc = _unixLogErrorAtLine(tls, libc.Int32FromInt32(SQLITE_IOERR)|libc.Int32FromInt32(19)<<libc.Int32FromInt32(8), __ccgo_ts+3613, zFile, int32(45381))
							goto shmpage_out
						}
						goto _1
					_1:
						;
						iPg = iPg + 1
					}
				}
			}
		}
		/* Map the requested memory region into this processes address space. */
		apNew = Xsqlite3_realloc64(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FapRegion, uint64(libc.Uint64FromInt32(nReqRegion)*uint64(8)))
		if !(apNew != 0) {
			rc = libc.Int32FromInt32(SQLITE_IOERR) | libc.Int32FromInt32(12)<<libc.Int32FromInt32(8)
			goto shmpage_out
		}
		(*TunixShmNode)(unsafe.Pointer(pShmNode)).FapRegion = apNew
		for libc.Int32FromUint16((*TunixShmNode)(unsafe.Pointer(pShmNode)).FnRegion) < nReqRegion {
			nMap = int64(szRegion) * int64(nShmPerMap)
			if (*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm >= 0 {
				if (*TunixShmNode)(unsafe.Pointer(pShmNode)).FisReadonly != 0 {
					v2 = int32(PROT_READ)
				} else {
					v2 = libc.Int32FromInt32(PROT_READ) | libc.Int32FromInt32(PROT_WRITE)
				}
				pMem = (*(*func(*libc.TLS, uintptr, Tsize_t, int32, int32, int32, Toff_t) uintptr)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(22)].FpCurrent})))(tls, uintptr(0), libc.Uint64FromInt64(nMap), v2, int32(MAP_SHARED), (*TunixShmNode)(unsafe.Pointer(pShmNode)).FhShm, int64(int64(szRegion)*libc.Int64FromUint16((*TunixShmNode)(unsafe.Pointer(pShmNode)).FnRegion)))
				if pMem == uintptr(-libc.Int32FromInt32(1)) {
					rc = _unixLogErrorAtLine(tls, libc.Int32FromInt32(SQLITE_IOERR)|libc.Int32FromInt32(21)<<libc.Int32FromInt32(8), __ccgo_ts+3700, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FzFilename, int32(45408))
					goto shmpage_out
				}
			} else {
				pMem = Xsqlite3_malloc64(tls, libc.Uint64FromInt64(nMap))
				if pMem == uintptr(0) {
					rc = int32(SQLITE_NOMEM)
					goto shmpage_out
				}
				libc.Xmemset(tls, pMem, 0, libc.Uint64FromInt64(nMap))
			}
			i = 0
			for {
				if !(i < int64(nShmPerMap)) {
					break
				}
				**(**uintptr)(__ccgo_up((*TunixShmNode)(unsafe.Pointer(pShmNode)).FapRegion + uintptr(libc.Int64FromUint16((*TunixShmNode)(unsafe.Pointer(pShmNode)).FnRegion)+i)*8)) = pMem + uintptr(int64(szRegion)*i)
				goto _3
			_3:
				;
				i = i + 1
			}
			v4 = pShmNode + 32
			*(*Tu16)(unsafe.Pointer(v4)) = Tu16(int32(*(*Tu16)(unsafe.Pointer(v4))) + nShmPerMap)
		}
	}
	goto shmpage_out
shmpage_out:
	;
	if libc.Int32FromUint16((*TunixShmNode)(unsafe.Pointer(pShmNode)).FnRegion) > iRegion {
		**(**uintptr)(__ccgo_up(pp)) = **(**uintptr)(__ccgo_up((*TunixShmNode)(unsafe.Pointer(pShmNode)).FapRegion + uintptr(iRegion)*8))
	} else {
		**(**uintptr)(__ccgo_up(pp)) = uintptr(0)
	}
	if (*TunixShmNode)(unsafe.Pointer(pShmNode)).FisReadonly != 0 && rc == SQLITE_OK {
		rc = int32(SQLITE_READONLY)
	}
	Xsqlite3_mutex_leave(tls, (*TunixShmNode)(unsafe.Pointer(pShmNode)).FpShmMutex)
	return rc
}

// C documentation
//
//	/*
//	** Return the name of a directory in which to put temporary files.
//	** If no suitable temporary file directory can be found, return NULL.
//	*/
func _unixTempFileDir(tls *libc.TLS) (r uintptr) {
	bp := tls.Alloc(144)
	defer tls.Free(144)
	var i, v1 uint32
	var zDir uintptr
	var _ /* buf at bp+0 */ Tstat
	_, _, _ = i, zDir, v1
	i = uint32(0)
	zDir = Xsqlite3_temp_directory
	for int32(1) != 0 {
		if zDir != uintptr(0) && (*(*func(*libc.TLS, uintptr, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(4)].FpCurrent})))(tls, zDir, bp) == 0 && (**(**Tstat)(__ccgo_up(bp))).Fst_mode&uint32(S_IFMT) == uint32(S_IFDIR) && (*(*func(*libc.TLS, uintptr, int32) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(2)].FpCurrent})))(tls, zDir, int32(03)) == 0 {
			return zDir
		}
		if uint64(i) >= libc.Uint64FromInt64(48)/libc.Uint64FromInt64(8) {
			break
		}
		v1 = i
		i = i + 1
		zDir = _azTempDirs[v1]
	}
	return uintptr(0)
}

// C documentation
//
//	/*
//	** Check a unixFile that is a database.  Verify the following:
//	**
//	** (1) There is exactly one hard link on the file
//	** (2) The file is not a symbolic link
//	** (3) The file has not been renamed or unlinked
//	**
//	** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right.
//	*/
func _verifyDbFile(tls *libc.TLS, pFile uintptr) {
	bp := tls.Alloc(160)
	defer tls.Free(160)
	var rc int32
	var _ /* buf at bp+0 */ Tstat
	_ = rc
	/* These verifications occurs for the main database only */
	if libc.Int32FromUint16((*TunixFile)(unsafe.Pointer(pFile)).FctrlFlags)&int32(UNIXFILE_NOLOCK) != 0 {
		return
	}
	rc = (*(*func(*libc.TLS, int32, uintptr) int32)(unsafe.Pointer(&struct{ uintptr }{_aSyscall[int32(5)].FpCurrent})))(tls, (*TunixFile)(unsafe.Pointer(pFile)).Fh, bp)
	if rc != 0 {
		Xsqlite3_log(tls, int32(SQLITE_WARNING), __ccgo_ts+3836, libc.VaList(bp+152, (*TunixFile)(unsafe.Pointer(pFile)).FzPath))
		return
	}
	if (**(**Tstat)(__ccgo_up(bp))).Fst_nlink == uint64(0) {
		Xsqlite3_log(tls, int32(SQLITE_WARNING), __ccgo_ts+3860, libc.VaList(bp+152, (*TunixFile)(unsafe.Pointer(pFile)).FzPath))
		return
	}
	if (**(**Tstat)(__ccgo_up(bp))).Fst_nlink > uint64(1) {
		Xsqlite3_log(tls, int32(SQLITE_WARNING), __ccgo_ts+3889, libc.VaList(bp+152, (*TunixFile)(unsafe.Pointer(pFile)).FzPath))
		return
	}
	if _fileHasMoved(tls, pFile) != 0 {
		Xsqlite3_log(tls, int32(SQLITE_WARNING), __ccgo_ts+3916, libc.VaList(bp+152, (*TunixFile)(unsafe.Pointer(pFile)).FzPath))
		return
	}
}
