static void php_stat(const char *filename, php_stat_len filename_length, int type, pval *return_value) { struct stat *stat_sb; int rmask=S_IROTH,wmask=S_IWOTH,xmask=S_IXOTH; /* access rights defaults to other */ BLS_FETCH(); stat_sb = &BG(sb); if (!BG(CurrentStatFile) || strcmp(filename, BG(CurrentStatFile))) { if (!BG(CurrentStatFile) || filename_length > BG(CurrentStatLength)) { if (BG(CurrentStatFile)) { efree(BG(CurrentStatFile)); } BG(CurrentStatLength) = filename_length; BG(CurrentStatFile) = estrndup(filename, filename_length); } else { memcpy(BG(CurrentStatFile), filename, filename_length+1); } #if HAVE_SYMLINK BG(lsb).st_mode = 0; /* mark lstat buf invalid */ #endif if (VCWD_STAT(BG(CurrentStatFile), &BG(sb)) == -1) { if (!IS_LINK_OPERATION() && (type != 15 || errno != ENOENT)) { /* fileexists() test must print no error */ php_error(E_NOTICE,"stat failed for %s (errno=%d - %s)", BG(CurrentStatFile), errno, strerror(errno)); } efree(BG(CurrentStatFile)); BG(CurrentStatFile) = NULL; if (!IS_LINK_OPERATION()) { /* Don't require success for link operation */ RETURN_FALSE; } } } #if HAVE_SYMLINK if (IS_LINK_OPERATION() && !BG(lsb).st_mode) { /* do lstat if the buffer is empty */ if (VCWD_LSTAT(filename, &BG(lsb)) == -1) { php_error(E_NOTICE, "lstat failed for %s (errno=%d - %s)", filename, errno, strerror(errno)); RETURN_FALSE; } } #endif if (type >= 9 && type <= 11) { if(BG(sb).st_uid==getuid()) { rmask=S_IRUSR; wmask=S_IWUSR; xmask=S_IXUSR; } else if(BG(sb).st_gid==getgid()) { rmask=S_IRGRP; wmask=S_IWGRP; xmask=S_IXGRP; } else { int groups,n,i; gid_t *gids; groups = getgroups(0,NULL); if(groups) { gids=(gid_t *)emalloc(groups*sizeof(gid_t)); n=getgroups(groups,gids); for(i=0;i<n;i++){ if(BG(sb).st_gid==gids[i]) { rmask=S_IRGRP; wmask=S_IWGRP; xmask=S_IXGRP; break; } } efree(gids); } } } switch (type) { case 0: /* fileperms */ RETURN_LONG((long)BG(sb).st_mode); case 1: /* fileinode */ RETURN_LONG((long)BG(sb).st_ino); case 2: /* filesize */ RETURN_LONG((long)BG(sb).st_size); case 3: /* fileowner */ RETURN_LONG((long)BG(sb).st_uid); case 4: /* filegroup */ RETURN_LONG((long)BG(sb).st_gid); case 5: /* fileatime */ RETURN_LONG((long)BG(sb).st_atime); case 6: /* filemtime */ RETURN_LONG((long)BG(sb).st_mtime); case 7: /* filectime */ RETURN_LONG((long)BG(sb).st_ctime); case 8: /* filetype */ #if HAVE_SYMLINK if (S_ISLNK(BG(lsb).st_mode)) { RETURN_STRING("link",1); } #endif switch(BG(sb).st_mode&S_IFMT) { case S_IFIFO: RETURN_STRING("fifo",1); case S_IFCHR: RETURN_STRING("char",1); case S_IFDIR: RETURN_STRING("dir",1); case S_IFBLK: RETURN_STRING("block",1); case S_IFREG: RETURN_STRING("file",1); #if defined(S_IFSOCK) && !defined(ZEND_WIN32)&&!defined(__BEOS__) case S_IFSOCK: RETURN_STRING("socket",1); #endif } php_error(E_WARNING,"Unknown file type (%d)",BG(sb).st_mode&S_IFMT); RETURN_STRING("unknown", 1); case 9: /*is writable*/ if (getuid()==0) { RETURN_LONG(1); /* root */ } RETURN_LONG((BG(sb).st_mode & wmask) != 0); case 10: /*is readable*/ if (getuid()==0) { RETURN_LONG(1); /* root */ } RETURN_LONG((BG(sb).st_mode&rmask)!=0); case 11: /*is executable*/ if (getuid()==0) { xmask = S_IXROOT; /* root */ } RETURN_LONG((BG(sb).st_mode&xmask)!=0 && !S_ISDIR(BG(sb).st_mode)); case 12: /*is file*/ RETURN_LONG(S_ISREG(BG(sb).st_mode)); case 13: /*is dir*/ RETURN_LONG(S_ISDIR(BG(sb).st_mode)); case 14: /*is link*/ #if HAVE_SYMLINK RETURN_LONG(S_ISLNK(BG(lsb).st_mode)); #else RETURN_FALSE; #endif case 15: /*file exists*/ RETURN_TRUE; /* the false case was done earlier */ case 16: /* lstat */ #if HAVE_SYMLINK stat_sb = &BG(lsb); #endif /* FALLTHROUGH */ case 17: /* stat */ if (array_init(return_value) == FAILURE) { RETURN_FALSE; } add_next_index_long(return_value, stat_sb->st_dev); add_next_index_long(return_value, stat_sb->st_ino); add_next_index_long(return_value, stat_sb->st_mode); add_next_index_long(return_value, stat_sb->st_nlink); add_next_index_long(return_value, stat_sb->st_uid); add_next_index_long(return_value, stat_sb->st_gid); #ifdef HAVE_ST_RDEV add_next_index_long(return_value, stat_sb->st_rdev); #else add_next_index_long(return_value, -1); #endif add_next_index_long(return_value, stat_sb->st_size); add_next_index_long(return_value, stat_sb->st_atime); add_next_index_long(return_value, stat_sb->st_mtime); add_next_index_long(return_value, stat_sb->st_ctime); #ifdef HAVE_ST_BLKSIZE add_next_index_long(return_value, stat_sb->st_blksize); #else add_next_index_long(return_value, -1); #endif #ifdef HAVE_ST_BLOCKS add_next_index_long(return_value, stat_sb->st_blocks); #else add_next_index_long(return_value, -1); #endif /* Support string references as well as numerical*/ add_assoc_long ( return_value , "dev" , stat_sb->st_dev ); add_assoc_long ( return_value , "ino" , stat_sb->st_ino ); add_assoc_long ( return_value , "mode" , stat_sb->st_mode ); add_assoc_long ( return_value , "nlink" , stat_sb->st_nlink ); add_assoc_long ( return_value , "uid" , stat_sb->st_uid ); add_assoc_long ( return_value , "gid" , stat_sb->st_gid ); #ifdef HAVE_ST_RDEV add_assoc_long ( return_value, "rdev" , stat_sb->st_rdev ); #endif #ifdef HAVE_ST_BLKSIZE add_assoc_long ( return_value , "blksize" , stat_sb->st_blksize ); #endif add_assoc_long ( return_value , "size" , stat_sb->st_size ); add_assoc_long ( return_value , "atime" , stat_sb->st_atime ); add_assoc_long ( return_value , "mtime" , stat_sb->st_mtime ); add_assoc_long ( return_value , "ctime" , stat_sb->st_ctime ); #ifdef HAVE_ST_BLOCKS add_assoc_long ( return_value , "blocks" , stat_sb->st_blocks ); #endif return; } php_error(E_WARNING, "didn't understand stat call"); RETURN_FALSE; }
static void phar_file_stat(const char *filename, php_stat_len filename_length, int type, void (*orig_stat_func)(INTERNAL_FUNCTION_PARAMETERS), INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ { if (!filename_length) { RETURN_FALSE; } if (!IS_ABSOLUTE_PATH(filename, filename_length) && !strstr(filename, "://")) { char *arch, *entry, *fname; int arch_len, entry_len, fname_len; zend_stat_t sb = {0}; phar_entry_info *data = NULL; phar_archive_data *phar; fname = (char*)zend_get_executed_filename(); /* we are checking for existence of a file within the relative path. Chances are good that this is retrieving something from within the phar archive */ if (strncasecmp(fname, "phar://", 7)) { goto skip_phar; } fname_len = strlen(fname); if (PHAR_G(last_phar) && fname_len - 7 >= PHAR_G(last_phar_name_len) && !memcmp(fname + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) { arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len)); arch_len = PHAR_G(last_phar_name_len); entry = estrndup(filename, filename_length); /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */ entry_len = (int) filename_length; phar = PHAR_G(last_phar); goto splitted; } if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len, 2, 0)) { efree(entry); entry = estrndup(filename, filename_length); /* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */ entry_len = (int) filename_length; if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { efree(arch); efree(entry); goto skip_phar; } splitted: entry = phar_fix_filepath(entry, &entry_len, 1); if (entry[0] == '/') { if (NULL != (data = zend_hash_str_find_ptr(&(phar->manifest), entry + 1, entry_len - 1))) { efree(entry); goto stat_entry; } goto notfound; } if (NULL != (data = zend_hash_str_find_ptr(&(phar->manifest), entry, entry_len))) { efree(entry); goto stat_entry; } if (zend_hash_str_exists(&(phar->virtual_dirs), entry, entry_len)) { efree(entry); efree(arch); if (IS_EXISTS_CHECK(type)) { RETURN_TRUE; } sb.st_size = 0; sb.st_mode = 0777; sb.st_mode |= S_IFDIR; /* regular directory */ #ifdef NETWARE sb.st_mtime.tv_sec = phar->max_timestamp; sb.st_atime.tv_sec = phar->max_timestamp; sb.st_ctime.tv_sec = phar->max_timestamp; #else sb.st_mtime = phar->max_timestamp; sb.st_atime = phar->max_timestamp; sb.st_ctime = phar->max_timestamp; #endif goto statme_baby; } else { char *save; int save_len; notfound: efree(entry); save = PHAR_G(cwd); save_len = PHAR_G(cwd_len); /* this file is not in the current directory, use the original path */ entry = estrndup(filename, filename_length); entry_len = filename_length; PHAR_G(cwd) = "/"; PHAR_G(cwd_len) = 0; /* clean path without cwd */ entry = phar_fix_filepath(entry, &entry_len, 1); if (NULL != (data = zend_hash_str_find_ptr(&(phar->manifest), entry + 1, entry_len - 1))) { PHAR_G(cwd) = save; PHAR_G(cwd_len) = save_len; efree(entry); if (IS_EXISTS_CHECK(type)) { efree(arch); RETURN_TRUE; } goto stat_entry; } if (zend_hash_str_exists(&(phar->virtual_dirs), entry + 1, entry_len - 1)) { PHAR_G(cwd) = save; PHAR_G(cwd_len) = save_len; efree(entry); efree(arch); if (IS_EXISTS_CHECK(type)) { RETURN_TRUE; } sb.st_size = 0; sb.st_mode = 0777; sb.st_mode |= S_IFDIR; /* regular directory */ #ifdef NETWARE sb.st_mtime.tv_sec = phar->max_timestamp; sb.st_atime.tv_sec = phar->max_timestamp; sb.st_ctime.tv_sec = phar->max_timestamp; #else sb.st_mtime = phar->max_timestamp; sb.st_atime = phar->max_timestamp; sb.st_ctime = phar->max_timestamp; #endif goto statme_baby; } PHAR_G(cwd) = save; PHAR_G(cwd_len) = save_len; efree(entry); efree(arch); /* Error Occurred */ if (!IS_EXISTS_CHECK(type)) { php_error_docref(NULL, E_WARNING, "%sstat failed for %s", IS_LINK_OPERATION(type) ? "L" : "", filename); } RETURN_FALSE; } stat_entry: efree(arch); if (!data->is_dir) { sb.st_size = data->uncompressed_filesize; sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; if (data->link) { sb.st_mode |= S_IFREG|S_IFLNK; /* regular file */ } else { sb.st_mode |= S_IFREG; /* regular file */ } /* timestamp is just the timestamp when this was added to the phar */ #ifdef NETWARE sb.st_mtime.tv_sec = data->timestamp; sb.st_atime.tv_sec = data->timestamp; sb.st_ctime.tv_sec = data->timestamp; #else sb.st_mtime = data->timestamp; sb.st_atime = data->timestamp; sb.st_ctime = data->timestamp; #endif } else { sb.st_size = 0; sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; sb.st_mode |= S_IFDIR; /* regular directory */ if (data->link) { sb.st_mode |= S_IFLNK; } /* timestamp is just the timestamp when this was added to the phar */ #ifdef NETWARE sb.st_mtime.tv_sec = data->timestamp; sb.st_atime.tv_sec = data->timestamp; sb.st_ctime.tv_sec = data->timestamp; #else sb.st_mtime = data->timestamp; sb.st_atime = data->timestamp; sb.st_ctime = data->timestamp; #endif } statme_baby: if (!phar->is_writeable) { sb.st_mode = (sb.st_mode & 0555) | (sb.st_mode & ~0777); } sb.st_nlink = 1; sb.st_rdev = -1; /* this is only for APC, so use /dev/null device - no chance of conflict there! */ sb.st_dev = 0xc; /* generate unique inode number for alias/filename, so no phars will conflict */ if (data) { sb.st_ino = data->inode; } #ifndef PHP_WIN32 sb.st_blksize = -1; sb.st_blocks = -1; #endif phar_fancy_stat(&sb, type, return_value); return; } } skip_phar: orig_stat_func(INTERNAL_FUNCTION_PARAM_PASSTHRU); return; }