This is DirArray.m in view mode; [Download] [Up]
//=============================================================================
//
// Copyright (C) 1995-1997 by Paul S. McCarthy and Eric Sunshine.
// Written by Paul S. McCarthy and Eric Sunshine.
// All Rights Reserved.
//
// This notice may not be removed from this source code.
//
// This object is included in the MiscKit by permission from the authors
// and its use is governed by the MiscKit license, found in the file
// "License.rtf" in the MiscKit distribution. Please refer to that file
// for a list of all applicable permissions and restrictions.
//
//=============================================================================
//-----------------------------------------------------------------------------
// DirArray.m
//
// An extensible array of directory entries.
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// $Id: DirArray.m,v 1.2 97/06/10 04:53:13 sunshine Exp $
// $Log: DirArray.m,v $
// Revision 1.2 97/06/10 04:53:13 sunshine
// v15: Upgraded naming. Fixed bug: Wasn't taking sticky-bit into account
// when computing canToggleLock.
//
// Revision 1.1 97/02/05 08:22:38 sunshine
// v13: Synchronized with ScrollDir (v29). Added unscaledImage. Added
// isLocked & canToggleLock. Added manipulation methods. Supports file
// renaming.
//-----------------------------------------------------------------------------
#import "DirArray.h"
#import <appkit/Application.h>
#import <appkit/NXImage.h>
#import <appkit/workspaceRequest.h>
#import <assert.h>
#import <errno.h>
#import <libc.h>
#import <unistd.h>
#ifdef _POSIX_SOURCE
# define GRP_TYPE gid_t
# define MAX_GRPS NGROUPS_MAX
#else
# define GRP_TYPE int
# define MAX_GRPS NGROUPS
#endif
@implementation DirArray
//-----------------------------------------------------------------------------
// safeStrdup
//-----------------------------------------------------------------------------
- (char*)safeStrdup:(char const*)s
{
char* t = 0;
if (s != 0)
t = NXCopyStringBufferFromZone( s, [self zone] );
return t;
}
//-----------------------------------------------------------------------------
// safeFree
//-----------------------------------------------------------------------------
- (void)safeFree:(void*)p
{
if (p != 0)
NXZoneFree( [self zone], p );
}
//-----------------------------------------------------------------------------
// dirWritable:
//-----------------------------------------------------------------------------
- (BOOL)dirWritable:(char const*)path
{
BOOL rc = NO;
struct stat st;
if (stat( path, &st ) == 0)
{
unsigned int mode = st.st_mode;
if ((mode & 0002) != 0 || // "other"
((mode & 0200) != 0 && st.st_uid == geteuid())) // "owner"
rc = YES;
else if ((mode & 0020) != 0) // "group"
{
gid_t const gid = getegid();
if (st.st_gid == gid)
rc = YES;
else
{
GRP_TYPE groups[ MAX_GRPS ];
int n = getgroups( MAX_GRPS, groups );
while (n-- > 0)
if (gid == groups[n])
{ rc = YES; break; }
}
}
}
return rc;
}
//-----------------------------------------------------------------------------
// dirSticky:
//-----------------------------------------------------------------------------
- (BOOL)dirSticky:(char const*)path
{
struct stat st;
if (stat( path, &st ) == 0)
return ((st.st_mode & 01000) != 0);
return NO;
}
//-----------------------------------------------------------------------------
// dirEntryCons:name:path:isDotDot:
//-----------------------------------------------------------------------------
- (void)dirEntryCons:(DirEntry*)de name:(char const*)n path:(char const*)path
isDotDot:(BOOL)dotdot
{
int rc;
memset( de, 0, sizeof(*de) );
de->dir = self;
de->name = [self safeStrdup:n];
if ((rc = lstat( path, &(de->status) )) == 0)
{
unsigned int mode = de->status.st_mode;
if ((mode & S_IFMT) == S_IFLNK) // soft-link?
{
char symbuf[ FILENAME_MAX + 1 ];
int cc = readlink( path, symbuf, FILENAME_MAX );
if (cc >= 0)
{
struct stat st;
symbuf[ cc ] = '\0';
de->softLink = [self safeStrdup:symbuf];
if (stat( path, &st ) == 0)
mode = st.st_mode; // mode of file linked to
}
}
de->isDirectory = ((mode & S_IFMT) == S_IFDIR);
}
de->canToggleLock = (!dotdot && [self dirWritable] &&
(!sticky || de->status.st_uid == effectiveUid));
de->isLocked = !de->canToggleLock;
}
//-----------------------------------------------------------------------------
// freeImage
//-----------------------------------------------------------------------------
- (void)freeImage:(NXImage*)p
{
if (p != 0)
[p free];
}
//-----------------------------------------------------------------------------
// dirEntryDestroy:
//-----------------------------------------------------------------------------
- (void)dirEntryDestroy:(DirEntry*)de
{
[self freeImage:de->scaledImage];
[self freeImage:de->unscaledImage];
[self safeFree:de->name];
[self safeFree:de->softLink];
}
//-----------------------------------------------------------------------------
// entryAt:
//-----------------------------------------------------------------------------
- (DirEntry const*)entryAt:(int)n
{
assert( 0 <=n && n < numEntries );
return (entries + n);
}
//-----------------------------------------------------------------------------
// isDir:
//-----------------------------------------------------------------------------
- (BOOL)isDir:(DirEntry const*)de
{
return de->isDirectory;
}
//-----------------------------------------------------------------------------
// isDirAt:
//-----------------------------------------------------------------------------
- (BOOL)isDirAt:(int)n
{
return [self isDir:[self entryAt:n]];
}
//-----------------------------------------------------------------------------
// canToggleLock:
//-----------------------------------------------------------------------------
- (BOOL)canToggleLock:(DirEntry const*)de
{
return de->canToggleLock;
}
//-----------------------------------------------------------------------------
// canToggleLockAt:
//-----------------------------------------------------------------------------
- (BOOL)canToggleLockAt:(int)n
{
return [self canToggleLock:[self entryAt:n]];
}
//-----------------------------------------------------------------------------
// isLocked:
//-----------------------------------------------------------------------------
- (BOOL)isLocked:(DirEntry const*)de
{
return de->isLocked;
}
//-----------------------------------------------------------------------------
// isLockedAt:
//-----------------------------------------------------------------------------
- (BOOL)isLockedAt:(int)n
{
return [self isLocked:[self entryAt:n]];
}
//-----------------------------------------------------------------------------
// setLocked:at:
//-----------------------------------------------------------------------------
- (void)setLocked:(BOOL)flag at:(int)n
{
assert( entries[n].canToggleLock );
entries[n].isLocked = flag;
}
//-----------------------------------------------------------------------------
// setName:at:
//-----------------------------------------------------------------------------
- (void)setName:(char const*)s at:(int)n
{
[self safeFree:entries[n].name];
entries[n].name = [self safeStrdup:s];
}
//-----------------------------------------------------------------------------
// loadImage:
//-----------------------------------------------------------------------------
- (void)loadImage:(DirEntry*)de
{
char buff[ FILENAME_MAX + 1 ];
char const* const dir_part = de->dir->name;
int const dirlen = strlen( dir_part );
memcpy( buff, dir_part, dirlen );
strcpy( buff + dirlen, de->name );
de->unscaledImage = [[Application workspace] getIconForFile:buff];
de->scaledImage = [de->unscaledImage copy];
[de->scaledImage setScalable:YES];
}
//-----------------------------------------------------------------------------
// getImage:scaled:
//-----------------------------------------------------------------------------
- (NXImage*)getImage:(DirEntry const*)de scaled:(BOOL)wantsScaled
{
if (de->unscaledImage == 0)
[self loadImage:(DirEntry*)de];
return (wantsScaled ? de->scaledImage : de->unscaledImage);
}
//-----------------------------------------------------------------------------
// getImageAt:scaled:
//-----------------------------------------------------------------------------
- (NXImage*)getImageAt:(int)n scaled:(BOOL)flag
{
return [self getImage:[self entryAt:n] scaled:flag];
}
//-----------------------------------------------------------------------------
// init
//-----------------------------------------------------------------------------
- (id)init
{
[super init];
totalBytes = 0;
numEntries = 0;
maxEntries = 0;
entries = 0;
writable = NO;
sticky = NO;
effectiveUid = geteuid();
return self;
}
//-----------------------------------------------------------------------------
// empty
//-----------------------------------------------------------------------------
- (void)empty
{
DirEntry* p;
for (p = entries + numEntries; p != entries; )
[self dirEntryDestroy:--p];
numEntries = 0;
totalBytes = 0;
}
//-----------------------------------------------------------------------------
// free
//-----------------------------------------------------------------------------
- (id)free
{
[self empty];
[self safeFree:name];
[self safeFree:entries];
return [super free];
}
//-----------------------------------------------------------------------------
// count
//-----------------------------------------------------------------------------
- (int)count
{
return numEntries;
}
//-----------------------------------------------------------------------------
// totalBytes
//-----------------------------------------------------------------------------
- (size_t)totalBytes
{
return totalBytes;
}
//-----------------------------------------------------------------------------
// dirWritable
//-----------------------------------------------------------------------------
- (BOOL)dirWritable
{
return writable;
}
//-----------------------------------------------------------------------------
// dirSticky
//-----------------------------------------------------------------------------
- (BOOL)dirSticky
{
return sticky;
}
//-----------------------------------------------------------------------------
// remove:
//-----------------------------------------------------------------------------
- (void)remove:(int)n
{
if (0 <= n && n < numEntries)
{
DirEntry* p = entries + n;
totalBytes -= p->status.st_size;
numEntries--;
[self dirEntryDestroy:p];
if (n < numEntries)
memmove( p, p + 1, (numEntries - n) * sizeof(*p) );
}
}
//-----------------------------------------------------------------------------
// expand
//-----------------------------------------------------------------------------
- (void)expand
{
DirEntry* p = entries;
int N = maxEntries;
if (N == 0)
{
N = 16;
p = (DirEntry*) NXZoneMalloc( [self zone], N * sizeof(*p) );
}
else
{
N += N;
p = (DirEntry*) NXZoneRealloc( [self zone], p, N * sizeof(*p) );
}
maxEntries = N;
entries = p;
}
//-----------------------------------------------------------------------------
// addName:path:isDotDot:
//-----------------------------------------------------------------------------
- (void)addName:(char const*)n path:(char const*)fullpath isDotDot:(BOOL)dotdot
{
DirEntry* p;
if (numEntries >= maxEntries)
[self expand];
p = entries + numEntries++;
[self dirEntryCons:p name:n path:fullpath isDotDot:dotdot];
totalBytes += p->status.st_size;
}
//-----------------------------------------------------------------------------
// loadPath:showHidden:
//-----------------------------------------------------------------------------
- (int)loadPath:(char const*)path showHidden:(BOOL)showHidden
{
int rc = 0;
int dirlen;
DIR* dirp;
char namebuff[ FILENAME_MAX + 1 ];
dirlen = strlen( path );
strcpy( namebuff, path );
if (dirlen == 0 || namebuff[ dirlen - 1 ] != '/')
{
namebuff[ dirlen++ ] = '/';
namebuff[ dirlen ] = '\0';
}
[self empty];
[self safeFree:name];
name = [self safeStrdup:namebuff];
writable = [self dirWritable:path];
sticky = [self dirSticky:path];
if ((dirp = opendir( path )) != 0)
{
struct direct const* dp;
while ((dp = readdir(dirp)) != 0)
{ // Do not include the "." (self) entry.
int const len = dp->d_namlen;
char const* const nam = dp->d_name;
BOOL const dot_name = (nam[0] == '.');
BOOL const dot_dot_name = (dot_name && len == 2 && nam[1] == '.');
if ((len > 1 || !dot_name) && // exclude "."
(showHidden || !dot_name || dot_dot_name)) // include ".."
{
memcpy( namebuff + dirlen, nam, len + 1 );
[self addName:nam path:namebuff isDotDot:dot_dot_name];
}
}
closedir( dirp );
}
else
rc = errno;
return rc;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.