/* * mdopen() -- Open the specified relation. ereport's on failure. * (Optionally, can return NULL instead of ereport for ENOENT.) * * Note we only open the first segment, when there are multiple segments. */ static MdfdVec * mdopen(SMgrRelation reln, bool allowNotFound) { MdfdVec *mdfd; char *path; File fd; /* No work if already open */ if (reln->md_fd) return reln->md_fd; path = relpath(reln->smgr_rnode); fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600); if (fd < 0) { /* * During bootstrap, there are cases where a system relation will be * accessed (by internal backend processes) before the bootstrap * script nominally creates it. Therefore, accept mdopen() as a * substitute for mdcreate() in bootstrap mode only. (See mdcreate) */ if (IsBootstrapProcessingMode()) fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600); if (fd < 0) { pfree(path); if (allowNotFound && errno == ENOENT) return NULL; ereport(ERROR, (errcode_for_file_access(), errmsg("could not open relation %u/%u/%u: %m", reln->smgr_rnode.spcNode, reln->smgr_rnode.dbNode, reln->smgr_rnode.relNode))); } } pfree(path); reln->md_fd = mdfd = _fdvec_alloc(); mdfd->mdfd_vfd = fd; mdfd->mdfd_segno = 0; #ifndef LET_OS_MANAGE_FILESIZE mdfd->mdfd_chain = NULL; Assert(_mdnblocks(fd, BLCKSZ) <= ((BlockNumber) RELSEG_SIZE)); #endif return mdfd; }
/* * mdopen() -- Open the specified relation. * * Note we only open the first segment, when there are multiple segments. * * If first segment is not present, either ereport or return NULL according * to "behavior". We treat EXTENSION_CREATE the same as EXTENSION_FAIL; * EXTENSION_CREATE means it's OK to extend an existing relation, not to * invent one out of whole cloth. */ static MdfdVec * mdopen(SMgrRelation reln, ForkNumber forknum, ExtensionBehavior behavior) { MdfdVec *mdfd; char *path; File fd; /* No work if already open */ if (reln->md_fd[forknum]) return reln->md_fd[forknum]; path = relpath(reln->smgr_rnode, forknum); fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600); if (fd < 0) { /* * During bootstrap, there are cases where a system relation will be * accessed (by internal backend processes) before the bootstrap * script nominally creates it. Therefore, accept mdopen() as a * substitute for mdcreate() in bootstrap mode only. (See mdcreate) */ if (IsBootstrapProcessingMode()) fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600); if (fd < 0) { if (behavior == EXTENSION_RETURN_NULL && FILE_POSSIBLY_DELETED(errno)) { pfree(path); return NULL; } ereport(ERROR, (errcode_for_file_access(), errmsg("could not open file \"%s\": %m", path))); } } pfree(path); reln->md_fd[forknum] = mdfd = _fdvec_alloc(); mdfd->mdfd_vfd = fd; mdfd->mdfd_segno = 0; mdfd->mdfd_chain = NULL; Assert(_mdnblocks(reln, forknum, mdfd) <= ((BlockNumber) RELSEG_SIZE)); return mdfd; }
/* * mdcreate() -- Create a new relation on magnetic disk. * * If isRedo is true, it's okay for the relation to exist already. */ bool mdcreate(SMgrRelation reln, bool isRedo) { char *path; File fd; if (isRedo && reln->md_fd != NULL) return true; /* created and opened already... */ Assert(reln->md_fd == NULL); path = relpath(reln->smgr_rnode); fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600); if (fd < 0) { int save_errno = errno; /* * During bootstrap, there are cases where a system relation will be * accessed (by internal backend processes) before the bootstrap * script nominally creates it. Therefore, allow the file to exist * already, even if isRedo is not set. (See also mdopen) */ if (isRedo || IsBootstrapProcessingMode()) fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600); if (fd < 0) { pfree(path); /* be sure to return the error reported by create, not open */ errno = save_errno; return false; } errno = 0; } pfree(path); reln->md_fd = _fdvec_alloc(); reln->md_fd->mdfd_vfd = fd; reln->md_fd->mdfd_segno = 0; #ifndef LET_OS_MANAGE_FILESIZE reln->md_fd->mdfd_chain = NULL; #endif return true; }
/* * Do open the next segment file to read, but don't do error processing. * */ static File ParquetStorageRead_DoOpenFile(ParquetStorageRead *storageRead, char *filePathName) { int fileFlags = O_RDONLY | PG_BINARY; int fileMode = 0400; /* File mode is S_IRUSR 00400 user has read permission */ File file; Assert(storageRead != NULL); Assert(storageRead->isActive); Assert(filePathName != NULL); if (Debug_appendonly_print_read_block) { elog( LOG, "Parquet storage read: opening table '%s', segment file '%s', fileFlags 0x%x, fileMode 0x%x", storageRead->relationName, storageRead->segmentFileName, fileFlags, fileMode); } /* * Open the file for read. */ file = PathNameOpenFile(filePathName, fileFlags, fileMode); return file; }
/* * Do open the next segment file to read, but don't do error processing. * * This routine is responsible for seeking to the proper * read location given the logical EOF. */ static File AppendOnlyStorageRead_DoOpenFile( AppendOnlyStorageRead *storageRead, char *filePathName) /* The name of the segment file to open. */ { int fileFlags = O_RDONLY | PG_BINARY; int fileMode = 0400; /* File mode is S_IRUSR 00400 user has read permission */ File file; Assert(storageRead != NULL); Assert(storageRead->isActive); Assert(filePathName != NULL); elogif(Debug_appendonly_print_read_block, LOG, "Append-Only storage read: opening table '%s', segment file '%s', fileFlags 0x%x, fileMode 0x%x", storageRead->relationName, storageRead->segmentFileName, fileFlags, fileMode); /* * Open the file for read. */ file = PathNameOpenFile(filePathName, fileFlags, fileMode); return file; }
static Oid lo_import_internal(text *filename, Oid lobjOid) { File fd; int nbytes, tmp; char buf[BUFSIZE]; char fnamebuf[MAXPGPATH]; LargeObjectDesc *lobj; Oid oid; #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to use server-side lo_import()"), errhint("Anyone can use the client-side lo_import() provided by libpq."))); #endif CreateFSContext(); /* * open the file to be read in */ text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, S_IRWXU); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open server file \"%s\": %m", fnamebuf))); /* * create an inversion object */ oid = inv_create(lobjOid); /* * read in from the filesystem and write to the inversion object */ lobj = inv_open(oid, INV_WRITE, fscxt); while ((nbytes = FileRead(fd, buf, BUFSIZE)) > 0) { tmp = inv_write(lobj, buf, nbytes); Assert(tmp == nbytes); } if (nbytes < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not read server file \"%s\": %m", fnamebuf))); inv_close(lobj); FileClose(fd); return oid; }
/* * mdcreate() -- Create a new relation on magnetic disk. * * If isRedo is true, it's okay for the relation to exist already. */ void mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo) { char *path; File fd; if (isRedo && reln->md_fd[forkNum] != NULL) return; /* created and opened already... */ Assert(reln->md_fd[forkNum] == NULL); path = relpath(reln->smgr_rnode, forkNum); fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600); if (fd < 0) { int save_errno = errno; /* * During bootstrap, there are cases where a system relation will be * accessed (by internal backend processes) before the bootstrap * script nominally creates it. Therefore, allow the file to exist * already, even if isRedo is not set. (See also mdopen) */ if (isRedo || IsBootstrapProcessingMode()) fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600); if (fd < 0) { /* be sure to report the error reported by create, not open */ errno = save_errno; ereport(ERROR, (errcode_for_file_access(), errmsg("could not create file \"%s\": %m", path))); } } pfree(path); reln->md_fd[forkNum] = _fdvec_alloc(); reln->md_fd[forkNum]->mdfd_vfd = fd; reln->md_fd[forkNum]->mdfd_segno = 0; reln->md_fd[forkNum]->mdfd_chain = NULL; }
static void DatabaseInfo_AddFile( DatabaseInfo *info, HTAB *dbInfoRelHashTable, Oid tablespace, char *dbDirPath, char *name) { int64 eof; int itemCount; Oid relfilenode; uint32 segmentFileNum; char path[MAXPGPATH]; int fileFlags = O_RDONLY | PG_BINARY; int fileMode = 0400; /* File mode is S_IRUSR 00400 user has read permission */ File file; sprintf(path, "%s/%s", dbDirPath, name); /* * Open the file for read. */ file = PathNameOpenFile(path, fileFlags, fileMode); if(file < 0) { ereport(ERROR, (errcode_for_file_access(), errmsg("Could not open segment file '%s'", path))); } eof = FileSeek(file, 0L, SEEK_END); if (eof < 0) { ereport(ERROR, (errcode_for_file_access(), errmsg("Could not seek to end of file \"%s\" : %m", path))); } FileClose(file); itemCount = sscanf(name, "%u.%u", &relfilenode, &segmentFileNum); // UNDONE: sscanf is a rather poor scanner. // UNDONE: For right now, just assume properly named files.... if (itemCount == 0) { DatabaseInfo_AddMiscEntry(info, tablespace, false, name); return; } else if (itemCount == 1) segmentFileNum = 0; else Assert(itemCount == 2); DatabaseInfo_AddRelSegFile(info, dbInfoRelHashTable, tablespace, relfilenode, segmentFileNum, eof); }
/* * open a file in the database directory ($PGDATA/base/DIROID/) * * if we are using the system default filespace. Otherwise open * the file in the filespace configured for temporary files. * The passed name MUST be a relative path. Effectively, this * prepends DatabasePath or path of the filespace to it and then * acts like PathNameOpenFile. */ File FileNameOpenFile(FileName fileName, int fileFlags, int fileMode) { File fd; char *fname; Assert(!is_absolute_path(fileName)); fname = (char*)palloc(PATH_MAX); if (snprintf(fname, PATH_MAX, "%s/%s", getCurrentTempFilePath, fileName) > PATH_MAX) { ereport(ERROR, (errmsg("cannot generate path %s/%s", getCurrentTempFilePath, fileName))); } fd = PathNameOpenFile(fname, fileFlags, fileMode); pfree(fname); return fd; }
/* * Open the specified segment of the relation, * and make a MdfdVec object for it. Returns NULL on failure. */ static MdfdVec * _mdfd_openseg(SMgrRelation reln, BlockNumber segno, int oflags) { MdfdVec *v; int fd; char *path, *fullpath; path = relpath(reln->smgr_rnode); if (segno > 0) { /* be sure we have enough space for the '.segno' */ fullpath = (char *) palloc(strlen(path) + 12); sprintf(fullpath, "%s.%u", path, segno); pfree(path); } else fullpath = path; /* open the file */ fd = PathNameOpenFile(fullpath, O_RDWR | PG_BINARY | oflags, 0600); pfree(fullpath); if (fd < 0) return NULL; /* allocate an mdfdvec entry for it */ v = _fdvec_alloc(); /* fill the entry */ v->mdfd_vfd = fd; v->mdfd_segno = segno; v->mdfd_chain = NULL; Assert(_mdnblocks(fd, BLCKSZ) <= ((BlockNumber) RELSEG_SIZE)); /* all done */ return v; }
/* * lo_export - * exports an (inversion) large object. */ Datum lo_export(PG_FUNCTION_ARGS) { Oid lobjId = PG_GETARG_OID(0); text *filename = PG_GETARG_TEXT_PP(1); File fd; int nbytes, tmp; char buf[BUFSIZE]; char fnamebuf[MAXPGPATH]; LargeObjectDesc *lobj; mode_t oumask; #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to use server-side lo_export()"), errhint("Anyone can use the client-side lo_export() provided by libpq."))); #endif CreateFSContext(); /* * open the inversion object (no need to test for failure) */ lobj = inv_open(lobjId, INV_READ, fscxt); /* * open the file to be written to * * Note: we reduce backend's normal 077 umask to the slightly friendlier * 022. This code used to drop it all the way to 0, but creating * world-writable export files doesn't seem wise. */ text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); oumask = umask(S_IWGRP | S_IWOTH); fd = PathNameOpenFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); umask(oumask); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create server file \"%s\": %m", fnamebuf))); /* * read in from the inversion file and write to the filesystem */ while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0) { tmp = FileWrite(fd, buf, nbytes); if (tmp != nbytes) ereport(ERROR, (errcode_for_file_access(), errmsg("could not write server file \"%s\": %m", fnamebuf))); } FileClose(fd); inv_close(lobj); PG_RETURN_INT32(1); }
/* * Open a temporary file in a specific tablespace. * Subroutine for OpenTemporaryFile, which see for details. */ static File OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError) { char tempdirpath[MAXPGPATH]; char tempfilepath[MAXPGPATH]; File file; /* * Identify the tempfile directory for this tablespace. * * If someone tries to specify pg_global, use pg_default instead. */ if (tblspcOid == DEFAULTTABLESPACE_OID || tblspcOid == GLOBALTABLESPACE_OID) { /* The default tablespace is {datadir}/base */ snprintf(tempdirpath, sizeof(tempdirpath), "base/%s", PG_TEMP_FILES_DIR); } else { /* All other tablespaces are accessed via symlinks */ snprintf(tempdirpath, sizeof(tempdirpath), "pg_tblspc/%u/%s", tblspcOid, PG_TEMP_FILES_DIR); } /* * Generate a tempfile name that should be unique within the current * database instance. */ snprintf(tempfilepath, sizeof(tempfilepath), "%s/%s%d.%ld", tempdirpath, PG_TEMP_FILE_PREFIX, MyProcPid, tempFileCounter++); /* * Open the file. Note: we don't use O_EXCL, in case there is an orphaned * temp file that can be reused. */ file = PathNameOpenFile(tempfilepath, O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600); if (file <= 0) { /* * We might need to create the tablespace's tempfile directory, if no * one has yet done so. * * Don't check for error from mkdir; it could fail if someone else * just did the same thing. If it doesn't work then we'll bomb out on * the second create attempt, instead. */ mkdir(tempdirpath, S_IRWXU); file = PathNameOpenFile(tempfilepath, O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600); if (file <= 0 && rejectError) elog(ERROR, "could not create temporary file \"%s\": %m", tempfilepath); } return file; }
/* * lo_import - * imports a file as an (inversion) large object. */ Datum lo_import(PG_FUNCTION_ARGS) { text *filename = PG_GETARG_TEXT_P(0); File fd; int nbytes, tmp; char buf[BUFSIZE]; char fnamebuf[MAXPGPATH]; LargeObjectDesc *lobj; Oid lobjOid; #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to use server-side lo_import()"), errhint("Anyone can use the client-side lo_import() provided by libpq."))); #endif CreateFSContext(); /* * open the file to be read in */ nbytes = VARSIZE(filename) - VARHDRSZ; if (nbytes >= MAXPGPATH) nbytes = MAXPGPATH - 1; memcpy(fnamebuf, VARDATA(filename), nbytes); fnamebuf[nbytes] = '\0'; fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open server file \"%s\": %m", fnamebuf))); /* * create an inversion object */ lobjOid = inv_create(InvalidOid); /* * read in from the filesystem and write to the inversion object */ lobj = inv_open(lobjOid, INV_WRITE, fscxt); while ((nbytes = FileRead(fd, buf, BUFSIZE)) > 0) { tmp = inv_write(lobj, buf, nbytes); Assert(tmp == nbytes); } if (nbytes < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not read server file \"%s\": %m", fnamebuf))); inv_close(lobj); FileClose(fd); PG_RETURN_OID(lobjOid); }
/* * Open a relation for mirrored write. */ static void MirroredBufferPool_DoOpen( MirroredBufferPoolOpen *open, /* The resulting open struct. */ RelFileNode *relFileNode, /* The tablespace, database, and relation OIDs for the open. */ uint32 segmentFileNum, /* Which segment file. */ char *relationName, /* For tracing only. Can be NULL in some execution paths. */ MirrorDataLossTrackingState mirrorDataLossTrackingState, int64 mirrorDataLossTrackingSessionNum, bool create, bool mirrorOnly, bool copyToMirror, int *primaryError, bool *mirrorDataLossOccurred) { int fileFlags = O_RDWR | PG_BINARY; int fileMode = 0600; /* * File mode is S_IRUSR 00400 user has read permission * + S_IWUSR 00200 user has write permission */ char *primaryFilespaceLocation = NULL; char *mirrorFilespaceLocation = NULL; Assert(open != NULL); *primaryError = 0; *mirrorDataLossOccurred = false; if (create) fileFlags = O_CREAT | O_RDWR | PG_BINARY; PersistentTablespace_GetPrimaryAndMirrorFilespaces( relFileNode->spcNode, &primaryFilespaceLocation, &mirrorFilespaceLocation); if (Debug_persistent_print && (create || mirrorOnly || copyToMirror)) { SUPPRESS_ERRCONTEXT_DECLARE; SUPPRESS_ERRCONTEXT_PUSH(); elog(Persistent_DebugPrintLevel(), "MirroredBufferPool_DoOpen: Special open %u/%u/%u --> create %s, mirrorOnly %s, copyToMirror %s, " "primary filespace location %s " "mirror filespace location %s ", relFileNode->spcNode, relFileNode->dbNode, relFileNode->relNode, (create ? "true" : "false"), (mirrorOnly ? "true" : "false"), (copyToMirror ? "true" : "false"), (primaryFilespaceLocation == NULL) ? "<null>" : primaryFilespaceLocation, (mirrorFilespaceLocation == NULL) ? "<null>" : mirrorFilespaceLocation); SUPPRESS_ERRCONTEXT_POP(); } MemSet(open, 0, sizeof(MirroredBufferPoolOpen)); open->primaryFile = -1; if (mirrorFilespaceLocation == NULL) sprintf(open->mirrorFilespaceLocation, "%s", ""); else sprintf(open->mirrorFilespaceLocation, "%s", mirrorFilespaceLocation); open->relFileNode = *relFileNode; open->segmentFileNum = segmentFileNum; open->create = create; open->mirrorOnly = mirrorOnly; open->copyToMirror = copyToMirror; MirroredBufferPool_SetUpMirrorAccess( relFileNode, segmentFileNum, relationName, mirrorDataLossTrackingState, mirrorDataLossTrackingSessionNum, /* primaryOnly */ false, mirrorOnly, &open->mirrorMode, &open->mirrorDataLossOccurred); if (StorageManagerMirrorMode_DoPrimaryWork(open->mirrorMode)) { char *dbPath; char *path; dbPath = (char*)palloc(MAXPGPATH + 1); path = (char*)palloc(MAXPGPATH + 1); /* * Do the primary work first so we don't leave files on the mirror or have an * open to clean up. */ FormDatabasePath( dbPath, primaryFilespaceLocation, relFileNode->spcNode, relFileNode->dbNode); if (segmentFileNum == 0) sprintf(path, "%s/%u", dbPath, relFileNode->relNode); else sprintf(path, "%s/%u.%u", dbPath, relFileNode->relNode, segmentFileNum); errno = 0; open->primaryFile = PathNameOpenFile(path, fileFlags, fileMode); if (open->primaryFile < 0) { *primaryError = errno; } pfree(dbPath); pfree(path); } if (StorageManagerMirrorMode_SendToMirror(open->mirrorMode) && *primaryError == 0 && !open->mirrorDataLossOccurred) { if (FileRepPrimary_MirrorOpen( FileRep_GetRelationIdentifier( open->mirrorFilespaceLocation, open->relFileNode, open->segmentFileNum), FileRepRelationTypeBufferPool, FILEREP_OFFSET_UNDEFINED, fileFlags, fileMode, TRUE /* supressError */) != 0) { if (Debug_filerep_print) ereport(LOG, (errmsg("could not sent file open request to mirror "), FileRep_ReportRelationPath( open->mirrorFilespaceLocation, open->relFileNode, open->segmentFileNum))); } open->mirrorDataLossOccurred = FileRepPrimary_IsMirrorDataLossOccurred(); } if (*primaryError != 0) { open->isActive = false; } else if (StorageManagerMirrorMode_DoPrimaryWork(open->mirrorMode)) { open->isActive = true; } else if (StorageManagerMirrorMode_SendToMirror(open->mirrorMode) && !open->mirrorDataLossOccurred) { open->isActive = true; } *mirrorDataLossOccurred = open->mirrorDataLossOccurred; if (primaryFilespaceLocation != NULL) pfree(primaryFilespaceLocation); if (mirrorFilespaceLocation != NULL) pfree(mirrorFilespaceLocation); }