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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 =-
|
||||||
|
|||||||
@@ -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).
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
return -1;
|
||||||
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 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;
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -191,16 +234,30 @@ zip_fstat(uio_Handle *handle, struct stat *statBuf) {
|
|||||||
int
|
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;
|
||||||
|
|
||||||
entry = uio_GPDir_getGPDirEntry(pDirHandle->extra, name);
|
if (name[0] == '.' && name[1] == '\0') {
|
||||||
if (entry == NULL) {
|
entry = (uio_GPDirEntry *) pDirHandle->extra;
|
||||||
errno = ENOENT;
|
} else {
|
||||||
return -1;
|
entry = uio_GPDir_getGPDirEntry(pDirHandle->extra, name);
|
||||||
|
if (entry == NULL) {
|
||||||
|
errno = ENOENT;
|
||||||
|
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;
|
||||||
|
|
||||||
@@ -647,8 +689,9 @@ zip_fillDirStructureCentralProcessFile(uio_GPDir *topGPDir,
|
|||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
@@ -726,19 +771,45 @@ 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 (zip_foundFile(topGPDir, fileName, gPFileData) == -1) {
|
if (S_ISREG(gPFileData->mode)) {
|
||||||
if (errno == EISDIR) {
|
if (zip_foundFile(topGPDir, fileName, gPFileData) == -1) {
|
||||||
zip_GPFileData_delete(gPFileData);
|
if (errno == EISDIR) {
|
||||||
uio_free(fileName);
|
fprintf(stderr, "Warning: file '%s' already exists as a dir - "
|
||||||
return 0;
|
"skipped.\n", fileName);
|
||||||
|
zip_GPFileData_delete(gPFileData);
|
||||||
|
uio_free(fileName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return zip_badFile(gPFileData, fileName);
|
||||||
}
|
}
|
||||||
return zip_badFile(gPFileData, fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
#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,31 +1144,84 @@ 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 (zip_foundFile(topGPDir, fileName, gPFileData) == -1) {
|
if (S_ISREG(gPFileData->mode)) {
|
||||||
if (errno == EISDIR) {
|
if (zip_foundFile(topGPDir, fileName, gPFileData) == -1) {
|
||||||
zip_GPFileData_delete(gPFileData);
|
if (errno == EISDIR) {
|
||||||
uio_free(fileName);
|
fprintf(stderr, "Warning: file '%s' already exists as a dir - "
|
||||||
return 0;
|
"skipped.\n", fileName);
|
||||||
|
zip_GPFileData_delete(gPFileData);
|
||||||
|
uio_free(fileName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user