Better handing of directory permissions in .zip files.

This is a general uio improvement that is not actually used in uqm.


git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1091 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
meep-eep
2003-07-29 18:49:35 +00:00
parent 2336893e50
commit 38c616078f
11 changed files with 407 additions and 99 deletions
+4 -16
View File
@@ -200,7 +200,7 @@ initRepository(void) {
#endif #endif
#if 1 #if 1
mountHandles[7] = debugMountOne(repository, "/foo/", mountHandles[7] = debugMountOne(repository, "/foo/",
uio_FSTYPE_ZIP, rootDir, "/foo.zip", "/", autoMount, uio_FSTYPE_ZIP, rootDir, "/foo2.zip", "/", autoMount,
uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL); uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL);
#endif #endif
uio_closeDir(rootDir); uio_closeDir(rootDir);
@@ -681,29 +681,18 @@ debugCmdRmDir(DebugContext *debugContext, int argc, char *argv[]) {
static int static int
debugCmdStat(DebugContext *debugContext, int argc, char *argv[]) { debugCmdStat(DebugContext *debugContext, int argc, char *argv[]) {
struct stat statBuf; struct stat statBuf;
uio_Handle *handle;
if (argc != 2) { if (argc != 2) {
fprintf(debugContext->err, "Invalid number of arguments.\n"); fprintf(debugContext->err, "Invalid number of arguments.\n");
return 1; return 1;
} }
handle = uio_open(debugContext->cwd, argv[1], O_RDONLY if (uio_stat(debugContext->cwd, argv[1], &statBuf) == -1) {
#ifdef WIN32
| O_BINARY
#endif
, 0);
if (handle == NULL) {
fprintf(debugContext->err, "Could not open file: %s\n",
strerror(errno));
return 1;
}
if (uio_fstat(handle, &statBuf) == -1) {
// errno is set // errno is set
int saveErrno; int saveErrno;
saveErrno = errno; saveErrno = errno;
uio_close(handle); fprintf(debugContext->err, "Could not stat file: %s\n",
strerror(errno));
errno = saveErrno; errno = saveErrno;
return 1; return 1;
} }
@@ -725,7 +714,6 @@ debugCmdStat(DebugContext *debugContext, int argc, char *argv[]) {
fprintf(debugContext->out, fprintf(debugContext->out,
"last status change: %s", ctime(&statBuf.st_ctime)); "last status change: %s", ctime(&statBuf.st_ctime));
uio_close(handle);
return 0; return 0;
} }
+1 -1
View File
@@ -15,7 +15,7 @@ earlier mounted file system, files in the later mounted file system hide
files in an earlier mounted file system. Files present in a filesystem files in an earlier mounted file system. Files present in a filesystem
mounted earlier that don't exist in a filesystem mounted later will remain mounted earlier that don't exist in a filesystem mounted later will remain
visible. visible.
Accessing compressed files inside compressde files is possible, though slow. Accessing compressed files inside compressed files is possible, though slow.
-= Nomenclature =- -= Nomenclature =-
+1
View File
@@ -29,6 +29,7 @@ Documentation:
fields. fields.
- No need to store MountHandles. They will be automatically freed - No need to store MountHandles. They will be automatically freed
when the repository is closed. when the repository is closed.
- You can use mount stuff from other repositories.
Bugs: Bugs:
- uio_Stream file might get unaligned (not sure). - uio_Stream file might get unaligned (not sure).
+1 -1
View File
@@ -172,9 +172,9 @@ struct uio_GPFile {
uio_GPDirEntry_COMMON uio_GPDirEntry_COMMON
# define uio_GPFile_NOCACHE uio_GPDirEntry_NOCACHE # define uio_GPFile_NOCACHE uio_GPDirEntry_NOCACHE
/* Info on this file will not be cached. */ /* Info on this file will not be cached. */
uio_PRoot *pRoot;
uio_GPFileExtra extra; uio_GPFileExtra extra;
/* extra internal data for some filesystem types */ /* extra internal data for some filesystem types */
uio_PRoot *pRoot;
}; };
+70 -12
View File
@@ -39,6 +39,10 @@
# include "memdebug.h" # include "memdebug.h"
#endif #endif
static int uio_statDir(uio_DirHandle *dirHandle, const char *path,
struct stat *statBuf);
static int uio_statOneDir(uio_PDirHandle *pDirHandle, struct stat *statBuf);
static void uio_PDirHandles_delete(uio_PDirHandle *pDirHandles[], static void uio_PDirHandles_delete(uio_PDirHandle *pDirHandles[],
int numPDirHandles); int numPDirHandles);
@@ -341,35 +345,89 @@ uio_stat(uio_DirHandle *dir, const char *path, struct stat *statBuf) {
char *name; char *name;
int result; int result;
// TODO: If it's a dir, check all physical dirs, and merge the
// direntry times.
if (uio_getPhysicalAccess(dir, path, O_RDONLY, if (uio_getPhysicalAccess(dir, path, O_RDONLY,
&readMountInfo, &pReadDir, &readMountInfo, &pReadDir,
NULL, NULL, &name) == -1) { NULL, NULL, &name) == -1) {
if (errno == EISDIR) { if (uio_statDir(dir, path, statBuf) == -1) {
// Need to merge the dirs. // errno is set
memset(statBuf, '\0', sizeof (struct stat));
statBuf->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR |
S_IRGRP | S_IWGRP | S_IXOTH |
S_IROTH | S_IWOTH | S_IXOTH;
statBuf->st_uid = 0;
statBuf->st_gid = 0;
return 0;
}
return -1; return -1;
} }
return 0;
}
if (pReadDir->pRoot->handler->stat == NULL) { if (pReadDir->pRoot->handler->stat == NULL) {
uio_PDirHandle_unref(pReadDir); uio_PDirHandle_unref(pReadDir);
uio_free(name);
errno = ENOSYS; errno = ENOSYS;
return -1; return -1;
} }
result = pReadDir->pRoot->handler->stat(pReadDir, name, statBuf); result = pReadDir->pRoot->handler->stat(pReadDir, name, statBuf);
uio_PDirHandle_unref(pReadDir); uio_PDirHandle_unref(pReadDir);
uio_free(name);
return result; return result;
} }
// auxiliary function to uio_stat
static int
uio_statDir(uio_DirHandle *dirHandle, const char *path,
struct stat *statBuf) {
int numPDirHandles;
uio_PDirHandle **pDirHandles;
if (uio_getPathPhysicalDirs(dirHandle, path, strlen(path),
&pDirHandles, &numPDirHandles, NULL) == -1) {
// errno is set
return -1;
}
if (numPDirHandles == 0) {
errno = ENOENT;
return -1;
}
if (uio_statOneDir(pDirHandles[0], statBuf) == -1) {
int saveErrno = errno;
uio_PDirHandles_delete(pDirHandles, numPDirHandles);
errno = saveErrno;
return -1;
}
// TODO: atm, fstat'ing a dir will show the info for the topmost
// dir. Maybe it would make sense of merging the bits. (How?)
#if 0
for (i = 1; i < numPDirHandles; i++) {
struct stat statOne;
uio_PDirHandle *pDirHandle;
if (statOneDir(pDirHandles[i], &statOne) == -1) {
// errno is set
int saveErrno = errno;
uio_PDirHandles_delete(pDirHandles, numPDirHandles);
errno = saveErrno;
return -1;
}
// Merge dirs:
}
#endif
uio_PDirHandles_delete(pDirHandles, numPDirHandles);
return 0;
}
static int
uio_statOneDir(uio_PDirHandle *pDirHandle, struct stat *statBuf) {
if (pDirHandle->pRoot->handler->stat == NULL) {
errno = ENOSYS;
return -1;
}
return pDirHandle->pRoot->handler->stat(pDirHandle, ".", statBuf);
// sets errno on error
}
int int
uio_mkdir(uio_DirHandle *dir, const char *path, mode_t mode) { uio_mkdir(uio_DirHandle *dir, const char *path, mode_t mode) {
uio_PDirHandle *pReadDir, *pWriteDir; uio_PDirHandle *pReadDir, *pWriteDir;
+4 -2
View File
@@ -484,8 +484,10 @@ uio_getPhysicalAccess(uio_DirHandle *dirHandle, const char *path,
// Get handles to the (existing) physical dirs that are effective in a // Get handles to the (existing) physical dirs that are effective in a
// path 'path' relative from 'dirHandle' // path 'path' relative from 'dirHandle'
// returns the PDirHandles through 'pDirHandles'. It is NULL if none were // returns the PDirHandles through '*pDirHandles'. It is NULL if none
// found. // were found.
// If resItems != NULL, it returns the MountTreeItems belonging to those
// PDIrHandles through *resItems. It is NULL if none were found.
// numPDirHandles will contain the number of PDirHandles found. // numPDirHandles will contain the number of PDirHandles found.
// returns 0 if everything went ok. // returns 0 if everything went ok.
// returns -1 in case of an error; errno is set. // returns -1 in case of an error; errno is set.
+1
View File
@@ -59,6 +59,7 @@ const uio_MemDebug_LogTypeInfo uio_MemDebug_logTypeInfo[] = {
{ "stdio_GPDirData", NULL, 0 }, { "stdio_GPDirData", NULL, 0 },
#ifdef HAVE_ZIP #ifdef HAVE_ZIP
{ "zip_GPFileData", NULL, 0 }, { "zip_GPFileData", NULL, 0 },
{ "zip_GPDirData", NULL, 0 },
#endif #endif
}; };
+1
View File
@@ -45,6 +45,7 @@ typedef enum {
uio_MemDebug_LogType_uio_Stream, uio_MemDebug_LogType_uio_Stream,
uio_MemDebug_LogType_stdio_GPDirData, uio_MemDebug_LogType_stdio_GPDirData,
uio_MemDebug_LogType_zip_GPFileData, uio_MemDebug_LogType_zip_GPFileData,
uio_MemDebug_LogType_zip_GPDirData,
uio_MemDebug_numLogTypes, /* This needs to be the last entry */ uio_MemDebug_numLogTypes, /* This needs to be the last entry */
} uio_MemDebug_LogType; } uio_MemDebug_LogType;
+1 -1
View File
@@ -91,7 +91,7 @@ struct uio_Stream {
char *bufEnd; char *bufEnd;
off_t seekLow; off_t seekLow;
// Low(er) level file pointer. Always points to the position just // Low(er) level file pointer. Always points to the position just
// past the part that's in the buffer. // past the part that's in the buffer as [readStart..readEnd].
uio_Handle *handle; uio_Handle *handle;
int status; int status;
#define uio_Stream_STATUS_OK 0 #define uio_Stream_STATUS_OK 0
+294 -42
View File
@@ -58,13 +58,17 @@ static int zip_fillDirStructureCentralProcessFile(uio_GPDir *topGPDir,
uio_FileBlock *fileBlock, off_t *pos); uio_FileBlock *fileBlock, off_t *pos);
static int zip_updatePFileDataFromLocalFileHeader(zip_GPFileData *gPFileData, static int zip_updatePFileDataFromLocalFileHeader(zip_GPFileData *gPFileData,
uio_FileBlock *fileBlock, int pos); uio_FileBlock *fileBlock, int pos);
int zip_updateFileDataFromLocalHeader(uio_Handle *handle,
zip_GPFileData *gPFileData);
#endif #endif
static int zip_fillDirStructureProcessExtraFields( static int zip_fillDirStructureProcessExtraFields(
uio_FileBlock *fileBlock, off_t extraFieldLength, uio_FileBlock *fileBlock, off_t extraFieldLength,
zip_GPFileData *gPFileData, const char *fileName, off_t pos); zip_GPFileData *gPFileData, const char *path, off_t pos,
static inline int zip_foundFile(uio_GPDir *gPDir, const char *fileName, uio_bool central);
static inline int zip_foundFile(uio_GPDir *gPDir, const char *path,
zip_GPFileData *gPFileData); zip_GPFileData *gPFileData);
//static inline uio_GPDir *zip_foundDir(uio_GPDir *gPDir, const char *dirName); static inline int zip_foundDir(uio_GPDir *gPDir, const char *dirName,
zip_GPDirData *gPDirData);
static int zip_initZipStream(z_stream *zipStream); static int zip_initZipStream(z_stream *zipStream);
static int zip_unInitZipStream(z_stream *zipStream); static int zip_unInitZipStream(z_stream *zipStream);
static int zip_reInitZipStream(z_stream *zipStream); static int zip_reInitZipStream(z_stream *zipStream);
@@ -76,6 +80,8 @@ static inline zip_GPFileData * zip_GPFileData_new(void);
static inline void zip_GPFileData_delete(zip_GPFileData *gPFileData); static inline void zip_GPFileData_delete(zip_GPFileData *gPFileData);
static inline zip_GPFileData *zip_GPFileData_alloc(void); static inline zip_GPFileData *zip_GPFileData_alloc(void);
static inline void zip_GPFileData_free(zip_GPFileData *gPFileData); static inline void zip_GPFileData_free(zip_GPFileData *gPFileData);
static inline void zip_GPDirData_delete(zip_GPDirData *gPDirData);
static inline void zip_GPDirData_free(zip_GPDirData *gPDirData);
static ssize_t zip_readStored(uio_Handle *handle, void *buf, size_t count); static ssize_t zip_readStored(uio_Handle *handle, void *buf, size_t count);
static ssize_t zip_readDeflated(uio_Handle *handle, void *buf, size_t count); static ssize_t zip_readDeflated(uio_Handle *handle, void *buf, size_t count);
@@ -114,7 +120,7 @@ uio_FileSystemHandler zip_fileSystemHandler = {
uio_GPRoot_Operations zip_GPRootOperations = { uio_GPRoot_Operations zip_GPRootOperations = {
/* .fillGPDir = */ NULL, /* .fillGPDir = */ NULL,
/* .deleteGPRootExtra = */ NULL, /* .deleteGPRootExtra = */ NULL,
/* .deleteGPDirExtra = */ NULL, /* .deleteGPDirExtra = */ zip_GPDirData_delete,
/* .deleteGPFileExtra = */ zip_GPFileData_delete, /* .deleteGPFileExtra = */ zip_GPFileData_delete,
}; };
@@ -151,6 +157,33 @@ zip_seekFunctionType zip_seekMethods[NUM_COMPRESSION_METHODS] = {
}; };
typedef enum {
zip_OSType_FAT,
zip_OSType_Amiga,
zip_OSType_OpenVMS,
zip_OSType_UNIX,
zip_OSType_VMCMS,
zip_OSType_AtariST,
zip_OSType_HPFS,
zip_OSType_HFS,
zip_OSType_ZSystem,
zip_OSType_CPM,
zip_OSType_TOPS20,
zip_OSType_NTFS,
zip_OSType_QDOS,
zip_OSType_Acorn,
zip_OSType_VFAT,
zip_OSType_MVS,
zip_OSType_BeOS,
zip_OSType_Tandem,
zip_numOSTypes
} zip_OSType;
#if zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS
static mode_t zip_makeFileMode(zip_OSType creatorOS, uio_uint32 modeBytes);
#endif
#define zip_INPUT_BUFFER_SIZE 0x10000 #define zip_INPUT_BUFFER_SIZE 0x10000
// TODO: make this configurable a la sysctl? // TODO: make this configurable a la sysctl?
#define zip_SEEK_BUFFER_SIZE zip_INPUT_BUFFER_SIZE #define zip_SEEK_BUFFER_SIZE zip_INPUT_BUFFER_SIZE
@@ -184,6 +217,16 @@ zip_fillStat(struct stat *statBuf, const zip_GPFileData *gPFileData) {
int int
zip_fstat(uio_Handle *handle, struct stat *statBuf) { zip_fstat(uio_Handle *handle, struct stat *statBuf) {
#if zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS
if (handle->native->file->extra->fileOffset == -1) {
// The local header wasn't read in yet.
if (zip_updateFileDataFromLocalHeader(handle->root->handle,
handle->native->file->extra) == -1) {
// errno is set
return -1;
}
}
#endif
zip_fillStat(statBuf, handle->native->file->extra); zip_fillStat(statBuf, handle->native->file->extra);
return 0; return 0;
} }
@@ -192,15 +235,29 @@ int
zip_stat(uio_PDirHandle *pDirHandle, const char *name, struct stat *statBuf) { zip_stat(uio_PDirHandle *pDirHandle, const char *name, struct stat *statBuf) {
uio_GPDirEntry *entry; uio_GPDirEntry *entry;
if (name[0] == '.' && name[1] == '\0') {
entry = (uio_GPDirEntry *) pDirHandle->extra;
} else {
entry = uio_GPDir_getGPDirEntry(pDirHandle->extra, name); entry = uio_GPDir_getGPDirEntry(pDirHandle->extra, name);
if (entry == NULL) { if (entry == NULL) {
errno = ENOENT; errno = ENOENT;
return -1; return -1;
} }
}
if (uio_GPDirEntry_isDir(entry)) { #if zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS
// No dir data is read from zip file. if (((zip_GPFileData *) entry->extra)->fileOffset == -1) {
// We'll have to make something up for the time being. // The local header wasn't read in yet.
if (zip_updateFileDataFromLocalHeader(pDirHandle->pRoot->handle,
(zip_GPFileData *) entry->extra) == -1) {
// errno is set
return -1;
}
}
#endif
if (uio_GPDirEntry_isDir(entry) && entry->extra == NULL) {
// No information about this directory was stored.
// We'll have to make something up.
memset(statBuf, '\0', sizeof (struct stat)); memset(statBuf, '\0', sizeof (struct stat));
statBuf->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | statBuf->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR |
S_IRGRP | S_IWGRP | S_IXOTH | S_IRGRP | S_IWGRP | S_IXOTH |
@@ -210,7 +267,7 @@ zip_stat(uio_PDirHandle *pDirHandle, const char *name, struct stat *statBuf) {
return 0; return 0;
} }
zip_fillStat(statBuf, ((uio_GPFile *) entry)->extra); zip_fillStat(statBuf, (zip_GPFileData *) entry->extra);
return 0; return 0;
} }
@@ -248,28 +305,12 @@ zip_open(uio_PDirHandle *pDirHandle, const char *name, int flags,
#if zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS #if zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS
if (gPFile->extra->fileOffset == -1) { if (gPFile->extra->fileOffset == -1) {
// the local header wasn't read in yet. // The local header wasn't read in yet.
uio_FileBlock *fileBlock; if (zip_updateFileDataFromLocalHeader(pDirHandle->pRoot->handle,
zip_GPFileData *gPFileData; gPFile->extra) == -1) {
fileBlock = uio_openFileBlock(pDirHandle->pRoot->handle);
if (fileBlock == NULL) {
// errno is set // errno is set
return NULL; return NULL;
} }
gPFileData = gPFile->extra;
if (zip_updatePFileDataFromLocalFileHeader(gPFileData,
fileBlock, gPFile->extra->headerOffset) == -1) {
int saveErrno = errno;
uio_closeFileBlock(fileBlock);
errno = saveErrno;
return NULL;
}
if (gPFileData->ctime == (time_t) 0)
gPFileData->ctime = gPFileData->mtime;
if (gPFileData->atime == (time_t) 0)
gPFileData->atime = gPFileData->mtime;
uio_closeFileBlock(fileBlock);
} }
#endif #endif
@@ -634,6 +675,7 @@ zip_fillDirStructureCentralProcessFile(uio_GPDir *topGPDir,
uio_uint16 extraFieldLength; uio_uint16 extraFieldLength;
uio_uint16 fileCommentLength; uio_uint16 fileCommentLength;
char *fileName; char *fileName;
zip_OSType creatorOS;
off_t nextEntryOffset; off_t nextEntryOffset;
@@ -649,6 +691,7 @@ zip_fillDirStructureCentralProcessFile(uio_GPDir *topGPDir,
} }
gPFileData = zip_GPFileData_new(); gPFileData = zip_GPFileData_new();
creatorOS = (zip_OSType) buf[5];
gPFileData->compressionFlags = makeUInt16(buf[8], buf[9]); gPFileData->compressionFlags = makeUInt16(buf[8], buf[9]);
gPFileData->compressionMethod = makeUInt16(buf[10], buf[11]); gPFileData->compressionMethod = makeUInt16(buf[10], buf[11]);
lastModTime = makeUInt16(buf[12], buf[13]); lastModTime = makeUInt16(buf[12], buf[13]);
@@ -656,9 +699,6 @@ zip_fillDirStructureCentralProcessFile(uio_GPDir *topGPDir,
gPFileData->atime = (time_t) 0; gPFileData->atime = (time_t) 0;
gPFileData->mtime = dosToUnixTime(lastModDate, lastModTime); gPFileData->mtime = dosToUnixTime(lastModDate, lastModTime);
gPFileData->ctime = (time_t) 0; gPFileData->ctime = (time_t) 0;
gPFileData->uid = 0;
gPFileData->gid = 0;
gPFileData->mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
crc = makeUInt32(buf[16], buf[17], buf[18], buf[19]); crc = makeUInt32(buf[16], buf[17], buf[18], buf[19]);
gPFileData->compressedSize = gPFileData->compressedSize =
makeUInt32(buf[20], buf[21], buf[22], buf[23]); makeUInt32(buf[20], buf[21], buf[22], buf[23]);
@@ -667,6 +707,11 @@ zip_fillDirStructureCentralProcessFile(uio_GPDir *topGPDir,
fileNameLength = makeUInt16(buf[28], buf[29]); fileNameLength = makeUInt16(buf[28], buf[29]);
extraFieldLength = makeUInt16(buf[30], buf[31]); extraFieldLength = makeUInt16(buf[30], buf[31]);
fileCommentLength = makeUInt16(buf[32], buf[33]); fileCommentLength = makeUInt16(buf[32], buf[33]);
gPFileData->uid = 0;
gPFileData->gid = 0;
gPFileData->mode = zip_makeFileMode(creatorOS,
makeUInt32(buf[38], buf[39], buf[40], buf[41]));
gPFileData->headerOffset = gPFileData->headerOffset =
(off_t) makeSInt32(buf[42], buf[43], buf[44], buf[45]); (off_t) makeSInt32(buf[42], buf[43], buf[44], buf[45]);
gPFileData->fileOffset = (off_t) -1; gPFileData->fileOffset = (off_t) -1;
@@ -710,7 +755,7 @@ zip_fillDirStructureCentralProcessFile(uio_GPDir *topGPDir,
} }
switch (zip_fillDirStructureProcessExtraFields(fileBlock, switch (zip_fillDirStructureProcessExtraFields(fileBlock,
extraFieldLength, gPFileData, fileName, *pos)) { extraFieldLength, gPFileData, fileName, *pos, true)) {
case 0: // file is ok case 0: // file is ok
break; break;
case 1: // file is not acceptable - skip file case 1: // file is not acceptable - skip file
@@ -727,8 +772,11 @@ zip_fillDirStructureCentralProcessFile(uio_GPDir *topGPDir,
// If ctime or atime is 0, they will be filled in when the local // If ctime or atime is 0, they will be filled in when the local
// file header is read. // file header is read.
if (S_ISREG(gPFileData->mode)) {
if (zip_foundFile(topGPDir, fileName, gPFileData) == -1) { if (zip_foundFile(topGPDir, fileName, gPFileData) == -1) {
if (errno == EISDIR) { if (errno == EISDIR) {
fprintf(stderr, "Warning: file '%s' already exists as a dir - "
"skipped.\n", fileName);
zip_GPFileData_delete(gPFileData); zip_GPFileData_delete(gPFileData);
uio_free(fileName); uio_free(fileName);
return 0; return 0;
@@ -739,6 +787,29 @@ zip_fillDirStructureCentralProcessFile(uio_GPDir *topGPDir,
#if defined(DEBUG) && DEBUG > 1 #if defined(DEBUG) && DEBUG > 1
fprintf(stderr, "Debug: Found file '%s'.\n", fileName); fprintf(stderr, "Debug: Found file '%s'.\n", fileName);
#endif #endif
} else if (S_ISDIR(gPFileData->mode)) {
if (fileName[fileNameLength - 1] == '/')
fileName[fileNameLength - 1] = '\0';
if (zip_foundDir(topGPDir, fileName, gPFileData) == -1) {
if (errno == EISDIR) {
fprintf(stderr, "Warning: file '%s' already exists as a dir - "
"skipped.\n", fileName);
zip_GPFileData_delete(gPFileData);
uio_free(fileName);
return 0;
}
return zip_badFile(gPFileData, fileName);
}
#if defined(DEBUG) && DEBUG > 1
fprintf(stderr, "Debug: Found dir '%s'.\n", fileName);
#endif
} else {
fprintf(stderr, "Warning: '%s' is not a regular file, nor a "
"directory - skipped.\n", fileName);
zip_GPFileData_delete(gPFileData);
uio_free(fileName);
return 0;
}
uio_free(fileName); uio_free(fileName);
return 0; return 0;
@@ -793,6 +864,43 @@ zip_findEndOfCentralDirectoryRecord(uio_Handle *handle,
return startPos + (bufPtr - buf); return startPos + (bufPtr - buf);
} }
static mode_t
zip_makeFileMode(zip_OSType creatorOS, uio_uint32 modeBytes) {
switch (creatorOS) {
case zip_OSType_FAT:
case zip_OSType_NTFS:
case zip_OSType_VFAT: {
mode_t mode;
if (modeBytes == 0) {
// File came from standard input
return S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH;
}
if (modeBytes & 0x00001000) {
// Directory
mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP |
S_IROTH | S_IXOTH;
} else {
// Regular file
mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
}
if (modeBytes & 0x00000100) {
// readonly
return mode;
} else {
// Write allowed
return mode | S_IWUSR | S_IWGRP | S_IWOTH;
}
}
case zip_OSType_UNIX:
return (mode_t) (modeBytes >> 16);
default:
fprintf(stderr, "Warning: file created by unknown OS.\n");
return S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
}
}
// If the data is read from the central directory, certain data // If the data is read from the central directory, certain data
// will need to be updated from the local directory when it is needed. // will need to be updated from the local directory when it is needed.
// This function does that. // This function does that.
@@ -824,7 +932,7 @@ zip_updatePFileDataFromLocalFileHeader(zip_GPFileData *gPFileData,
pos += 30 + fileNameLength; pos += 30 + fileNameLength;
switch (zip_fillDirStructureProcessExtraFields(fileBlock, switch (zip_fillDirStructureProcessExtraFields(fileBlock,
extraFieldLength, gPFileData, "<unknown>", pos)) { extraFieldLength, gPFileData, "<unknown>", pos, false)) {
case 0: // file is ok case 0: // file is ok
break; break;
case 1: case 1:
@@ -935,7 +1043,7 @@ zip_fillDirStructureLocalProcessFile(uio_GPDir *topGPDir,
gPFileData->ctime = (time_t) 0; gPFileData->ctime = (time_t) 0;
gPFileData->uid = 0; gPFileData->uid = 0;
gPFileData->gid = 0; gPFileData->gid = 0;
gPFileData->mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; gPFileData->mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
if (!isBitSet(gPFileData->compressionFlags, 3)) { if (!isBitSet(gPFileData->compressionFlags, 3)) {
// If bit 3 is not set, this info will be in the data descriptor // If bit 3 is not set, this info will be in the data descriptor
// behind the file data. // behind the file data.
@@ -983,13 +1091,18 @@ zip_fillDirStructureLocalProcessFile(uio_GPDir *topGPDir,
numBytes = uio_accessFileBlock(fileBlock, *pos, fileNameLength, &buf); numBytes = uio_accessFileBlock(fileBlock, *pos, fileNameLength, &buf);
if (numBytes != fileNameLength) if (numBytes != fileNameLength)
return zip_badFile(gPFileData, NULL); return zip_badFile(gPFileData, NULL);
*pos += fileNameLength;
if (buf[fileNameLength - 1] == '/') {
gPFileData->mode |= S_IFDIR;
fileNameLength--;
} else
gPFileData->mode |= S_IFREG;
fileName = uio_malloc(fileNameLength + 1); fileName = uio_malloc(fileNameLength + 1);
memcpy(fileName, buf, fileNameLength); memcpy(fileName, buf, fileNameLength);
fileName[fileNameLength] = '\0'; fileName[fileNameLength] = '\0';
*pos += fileNameLength;
switch (zip_fillDirStructureProcessExtraFields(fileBlock, switch (zip_fillDirStructureProcessExtraFields(fileBlock,
extraFieldLength, gPFileData, fileName, *pos)) { extraFieldLength, gPFileData, fileName, *pos, false)) {
case 0: // file is ok case 0: // file is ok
break; break;
case 1: // file is not acceptable - skip file case 1: // file is not acceptable - skip file
@@ -1031,8 +1144,11 @@ zip_fillDirStructureLocalProcessFile(uio_GPDir *topGPDir,
if (gPFileData->atime == (time_t) 0) if (gPFileData->atime == (time_t) 0)
gPFileData->atime = gPFileData->mtime; gPFileData->atime = gPFileData->mtime;
if (S_ISREG(gPFileData->mode)) {
if (zip_foundFile(topGPDir, fileName, gPFileData) == -1) { if (zip_foundFile(topGPDir, fileName, gPFileData) == -1) {
if (errno == EISDIR) { if (errno == EISDIR) {
fprintf(stderr, "Warning: file '%s' already exists as a dir - "
"skipped.\n", fileName);
zip_GPFileData_delete(gPFileData); zip_GPFileData_delete(gPFileData);
uio_free(fileName); uio_free(fileName);
return 0; return 0;
@@ -1040,22 +1156,72 @@ zip_fillDirStructureLocalProcessFile(uio_GPDir *topGPDir,
return zip_badFile(gPFileData, fileName); return zip_badFile(gPFileData, fileName);
} }
#ifdef DEBUG #if defined(DEBUG) && DEBUG > 1
fprintf(stderr, "Debug: Found file '%s'.\n", fileName); fprintf(stderr, "Debug: Found file '%s'.\n", fileName);
#endif #endif
} else if (S_ISDIR(gPFileData->mode)) {
if (fileName[fileNameLength - 1] == '/')
fileName[fileNameLength - 1] = '\0';
if (zip_foundDir(topGPDir, fileName, gPFileData) == -1) {
if (errno == EISDIR) {
fprintf(stderr, "Warning: file '%s' already exists as a dir - "
"skipped.\n", fileName);
zip_GPFileData_delete(gPFileData);
uio_free(fileName);
return 0;
}
return zip_badFile(gPFileData, fileName);
}
#if defined(DEBUG) && DEBUG > 1
fprintf(stderr, "Debug: Found dir '%s'.\n", fileName);
#endif
} else {
fprintf(stderr, "Warning: '%s' is not a regular file, nor a "
"directory - skipped.\n", fileName);
zip_GPFileData_delete(gPFileData);
uio_free(fileName);
return 0;
}
uio_free(fileName); uio_free(fileName);
return 0; return 0;
} }
#endif /* zip_USE_HEADERS == zip_USE_LOCAL_HEADERS */ #endif /* zip_USE_HEADERS == zip_USE_LOCAL_HEADERS */
#if zip_USE_HEADERS == zip_USE_CENTRAL_HEADERS
int
zip_updateFileDataFromLocalHeader(uio_Handle *handle,
zip_GPFileData *gPFileData) {
uio_FileBlock *fileBlock;
fileBlock = uio_openFileBlock(handle);
if (fileBlock == NULL) {
// errno is set
return -1;
}
if (zip_updatePFileDataFromLocalFileHeader(gPFileData,
fileBlock, gPFileData->headerOffset) == -1) {
int saveErrno = errno;
uio_closeFileBlock(fileBlock);
errno = saveErrno;
return -1;
}
if (gPFileData->ctime == (time_t) 0)
gPFileData->ctime = gPFileData->mtime;
if (gPFileData->atime == (time_t) 0)
gPFileData->atime = gPFileData->mtime;
uio_closeFileBlock(fileBlock);
return 0;
}
#endif
// If the zip file is bad, -1 is returned (no errno set!) // If the zip file is bad, -1 is returned (no errno set!)
// If the file in the zip file should be skipped, 1 is returned. // If the file in the zip file should be skipped, 1 is returned.
// If the file in the zip file is ok, 0 is returned. // If the file in the zip file is ok, 0 is returned.
static int static int
zip_fillDirStructureProcessExtraFields(uio_FileBlock *fileBlock, zip_fillDirStructureProcessExtraFields(uio_FileBlock *fileBlock,
off_t extraFieldLength, zip_GPFileData *gPFileData, off_t extraFieldLength, zip_GPFileData *gPFileData,
const char *fileName, off_t pos) { const char *fileName, off_t pos, uio_bool central) {
off_t posEnd; off_t posEnd;
uio_uint16 headerID; uio_uint16 headerID;
ssize_t dataSize; ssize_t dataSize;
@@ -1081,6 +1247,8 @@ zip_fillDirStructureProcessExtraFields(uio_FileBlock *fileBlock,
buf[0], buf[1], buf[2], buf[3]); buf[0], buf[1], buf[2], buf[3]);
gPFileData->mtime = (time_t) makeUInt32( gPFileData->mtime = (time_t) makeUInt32(
buf[4], buf[5], buf[6], buf[7]); buf[4], buf[5], buf[6], buf[7]);
if (central)
break;
if (dataSize > 8) { if (dataSize > 8) {
gPFileData->uid = (uid_t) makeUInt16(buf[8], buf[9]); gPFileData->uid = (uid_t) makeUInt16(buf[8], buf[9]);
gPFileData->gid = (uid_t) makeUInt16(buf[10], buf[11]); gPFileData->gid = (uid_t) makeUInt16(buf[10], buf[11]);
@@ -1098,6 +1266,13 @@ zip_fillDirStructureProcessExtraFields(uio_FileBlock *fileBlock,
bufPtr[0], bufPtr[1], bufPtr[2], bufPtr[3]); bufPtr[0], bufPtr[1], bufPtr[2], bufPtr[3]);
bufPtr += 4; bufPtr += 4;
} }
// The flags field, even in the central header, specifies what
// is present in the local header.
// The central header only contains a field for the mtime
// when it is present in the local header too, and
// never contains fields for other times.
if (central)
break;
if (isBitSet(flags, 1)) { if (isBitSet(flags, 1)) {
// modification time is present // modification time is present
gPFileData->atime = (time_t) makeUInt32( gPFileData->atime = (time_t) makeUInt32(
@@ -1108,15 +1283,17 @@ zip_fillDirStructureProcessExtraFields(uio_FileBlock *fileBlock,
break; break;
} }
case 0x7855: // 'Unix2' case 0x7855: // 'Unix2'
if (central)
break;
gPFileData->uid = (uid_t) makeUInt16(buf[0], buf[1]); gPFileData->uid = (uid_t) makeUInt16(buf[0], buf[1]);
gPFileData->gid = (uid_t) makeUInt16(buf[2], buf[3]); gPFileData->gid = (uid_t) makeUInt16(buf[2], buf[3]);
break; break;
case 0x756e: { // 'Unix3' case 0x756e: { // 'Unix3'
mode_t mode; mode_t mode;
mode = (mode_t) makeUInt16(buf[4], buf[5]); mode = (mode_t) makeUInt16(buf[4], buf[5]);
if (!S_ISREG(mode)) { if (!S_ISREG(mode) && !S_ISDIR(mode)) {
fprintf(stderr, "Warning: Skipping '%s'; not a regular " fprintf(stderr, "Warning: Skipping '%s'; not a regular "
"file.\n", fileName); "file, nor a directory.\n", fileName);
return 1; return 1;
} }
gPFileData->uid = (uid_t) makeUInt16(buf[10], buf[11]); gPFileData->uid = (uid_t) makeUInt16(buf[10], buf[11]);
@@ -1193,13 +1370,13 @@ zip_foundFile(uio_GPDir *gPDir, const char *path, zip_GPFileData *gPFileData) {
if (end == start || (end - start == 1 && start[0] == '.') || if (end == start || (end - start == 1 && start[0] == '.') ||
(end - start == 2 && start[0] == '.' && start[1] == '.')) { (end - start == 2 && start[0] == '.' && start[1] == '.')) {
fprintf(stderr, "Warning: file '%s' has an invalid path - " fprintf(stderr, "Warning: file '%s' has an invalid path - "
"file skipped.\n", path); "skipped.\n", path);
uio_free(buf); uio_free(buf);
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
if (end == pathEnd) { if (end == pathEnd) {
// This is the last component; the should be the name of the dir. // This is the last component; it should be the name of the dir.
path = start; path = start;
break; break;
} }
@@ -1207,7 +1384,7 @@ zip_foundFile(uio_GPDir *gPDir, const char *path, zip_GPFileData *gPFileData) {
buf[end - start] = '\0'; buf[end - start] = '\0';
newGPDir = uio_GPDir_prepareSubDir(gPDir, buf); newGPDir = uio_GPDir_prepareSubDir(gPDir, buf);
newGPDir->flags |= uio_GPDir_COMPLETE; newGPDir->flags |= uio_GPDir_COMPLETE;
// It will be complete when we're done with adding // It will be complete when we're done adding
// all files, and it won't be used before that. // all files, and it won't be used before that.
uio_GPDir_commitSubDir(gPDir, buf, newGPDir); uio_GPDir_commitSubDir(gPDir, buf, newGPDir);
@@ -1223,6 +1400,68 @@ zip_foundFile(uio_GPDir *gPDir, const char *path, zip_GPFileData *gPFileData) {
return 0; return 0;
} }
static inline int
zip_foundDir(uio_GPDir *gPDir, const char *path, zip_GPDirData *gPDirData) {
size_t pathLen;
const char *pathEnd;
const char *start, *end;
char *buf;
if (path[0] == '/')
path++;
pathLen = strlen(path);
pathEnd = path + pathLen;
switch (uio_walkGPPath(gPDir, path, pathLen, &gPDir, &path)) {
case 0:
// The dir already exists. Only need to add gPDirData
if (gPDir->extra) {
fprintf(stderr, "Warning: '%s' is present more than once "
"in the zip file. Last entry will be used.\n",
path);
zip_GPDirData_free(gPDir->extra);
}
gPDir->extra = gPDirData;
return 0;
case ENOTDIR:
fprintf(stderr, "Warning: A component of '%s' is not a "
"directory - file skipped.\n", path);
errno = ENOTDIR;
return -1;
case ENOENT:
break;
}
buf = uio_malloc(pathLen + 1);
getFirstPathComponent(path, pathEnd, &start, &end);
while (start < pathEnd) {
uio_GPDir *newGPDir;
if (end == start || (end - start == 1 && start[0] == '.') ||
(end - start == 2 && start[0] == '.' && start[1] == '.')) {
fprintf(stderr, "Warning: directory '%s' has an invalid path - "
"skipped.\n", path);
uio_free(buf);
errno = EINVAL;
return -1;
}
memcpy(buf, start, end - start);
buf[end - start] = '\0';
newGPDir = uio_GPDir_prepareSubDir(gPDir, buf);
newGPDir->flags |= uio_GPDir_COMPLETE;
// It will be complete when we're done adding
// all files, and it won't be used before that.
newGPDir->extra = gPDirData;
uio_GPDir_commitSubDir(gPDir, buf, newGPDir);
gPDir = newGPDir;
getNextPathComponent(pathEnd, &start, &end);
}
uio_free(buf);
return 0;
}
static int static int
zip_initZipStream(z_stream *zipStream) { zip_initZipStream(z_stream *zipStream) {
int retVal; int retVal;
@@ -1356,5 +1595,18 @@ zip_GPFileData_free(zip_GPFileData *gPFileData) {
uio_free(gPFileData); uio_free(gPFileData);
} }
static inline void
zip_GPDirData_delete(zip_GPDirData *gPDirData) {
zip_GPDirData_free(gPDirData);
}
static inline void
zip_GPDirData_free(zip_GPDirData *gPDirData) {
#ifdef uio_MEM_DEBUG
uio_MemDebug_debugFree(zip_GPFileData, (void *) gPDirData);
#endif
uio_free(gPDirData);
}
+6 -1
View File
@@ -20,8 +20,8 @@
typedef struct zip_Handle *uio_NativeHandle; typedef struct zip_Handle *uio_NativeHandle;
typedef void *uio_GPRootExtra; typedef void *uio_GPRootExtra;
typedef void *uio_GPDirExtra;
typedef struct zip_GPFileData *uio_GPFileExtra; typedef struct zip_GPFileData *uio_GPFileExtra;
typedef struct zip_GPFileData *uio_GPDirExtra;
typedef struct uio_GPDirEntries_Iterator *uio_NativeEntriesContext; typedef struct uio_GPDirEntries_Iterator *uio_NativeEntriesContext;
#define uio_INTERNAL_PHYSICAL #define uio_INTERNAL_PHYSICAL
@@ -64,6 +64,11 @@ typedef struct zip_GPFileData {
time_t ctime; // change time time_t ctime; // change time
} zip_GPFileData; } zip_GPFileData;
typedef zip_GPFileData zip_GPDirData;
// TODO: some of the fields from zip_GPFileData are not needed for
// directories. A few bytes could be saved here by making a seperate
// structure.
typedef struct zip_Handle { typedef struct zip_Handle {
uio_GPFile *file; uio_GPFile *file;
z_stream zipStream; z_stream zipStream;