/*#io File ioDoc( docCopyright("Steve Dekorte", 2002) docLicense("BSD revised") docCredits("Initial version contributed by Miles Egan.") */ #include "IoFile_stat.h" #include "IoState.h" #include "IoDate.h" #include #include #include #include #define DATA(self) ((IoFileData *)IoObject_dataPointer(self)) #ifndef lstat #define lstat stat #endif #ifndef S_ISDIR #define S_ISDIR(mode) ((mode & _S_IFDIR) != 0) #endif #ifndef S_ISFIFO #define S_ISFIFO(mode) ((mode & _S_IFIFO) != 0) #endif #ifndef S_ISREG #define S_ISREG(mode) ((mode & _S_IFREG) != 0) #endif #ifndef S_ISLNK #define S_ISLNK(mode) (0) #endif #ifndef S_ISSOCK #define S_ISSOCK(mode) (0) #endif #ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE #endif void IoFile_statInit(IoFile *self) { { IoMethodTable methodTable[] = { {"stat", IoFile_stat}, {"protectionMode", IoFile_protectionMode}, {"lastAccessDate", IoFile_lastAccessDate}, {"lastInfoChangeDate", IoFile_lastInfoChangeDate}, {"lastDataChangeDate", IoFile_lastDataChangeDate}, {"userId", IoFile_userId}, {"groupId", IoFile_groupId}, {"size", IoFile_statSize}, {"isDirectory", IoFile_isDirectory}, {"isPipe", IoFile_isPipe}, {"isLink", IoFile_isLink}, {"isRegularFile", IoFile_isRegularFile}, {"isSocket", IoFile_isSocket}, {"isUserExecutable", IoFile_isUserExecutable}, {NULL, NULL}, }; IoObject_addMethodTable_(self, methodTable); } } struct stat *IoFile_statPointer(IoFile *self, IoObject *locals, IoMessage *m) { if (!DATA(self)->info) { IoFile_stat(self, locals, m); } return (struct stat *)DATA(self)->info; } IoObject *IoFile_stat(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("stat", "Updates the receiver's meta info cache.") */ struct stat *statInfo; if (!DATA(self)->info) { DATA(self)->info = malloc(sizeof(struct stat)); } statInfo = DATA(self)->info; /* { char p[256]; sprintf(p, "touch %s", DATA(self)->path); system(p); } */ if (stat(CSTRING(DATA(self)->path), (struct stat *)(DATA(self)->info)) != 0) { IoState_error_(IOSTATE, m, "unable to stat '%s': %s", CSTRING(DATA(self)->path), strerror(errno)); } return self; } /* ---------------------------------- */ IoObject *IoFile_protectionMode(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("protectionMode", "Returns a Number containing the protection mode associated with the file's path.") */ return IONUMBER(IoFile_statPointer(self, locals, m)->st_mode); } #ifndef _POSIX_C_SOURCE struct timeval timespec2timeval(struct timespec ts) { struct timeval tv; tv.tv_sec = ts.tv_sec; tv.tv_usec = ts.tv_nsec / 1000; return tv; } #endif struct timeval time_t2timeval(time_t ts) { struct timeval tv; tv.tv_sec = ts; tv.tv_usec = 0; return tv; } IoObject *IoFile_lastAccessDate(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("lastAccessDate", "Returns a Date object containing the last date and time the file was accessed.") */ struct stat *s = IoFile_statPointer(self, locals, m); #ifndef _POSIX_C_SOURCE struct timeval tv = timespec2timeval(s->st_atimespec); #else struct timeval tv = time_t2timeval(s->st_atime); #endif return IoDate_newWithTimeval_(IOSTATE, tv); } IoObject *IoFile_lastInfoChangeDate(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("lastInfoChangeDate", "Returns a Date object containing the last date and time the file's meta info was changed.") */ struct stat *s = IoFile_statPointer(self, locals, m); #ifndef _POSIX_C_SOURCE struct timeval tv = timespec2timeval(s->st_ctimespec); #else struct timeval tv = time_t2timeval(s->st_ctime); #endif return IoDate_newWithTimeval_(IOSTATE, tv); } IoObject *IoFile_lastDataChangeDate(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("lastDataChangeDate", "Returns a Date object containing the last date and time the file's contents were changed.") */ struct stat *s = IoFile_statPointer(self, locals, m); #ifndef _POSIX_C_SOURCE struct timeval tv = timespec2timeval(s->st_mtimespec); #else struct timeval tv = time_t2timeval(s->st_mtime); #endif /* struct gettv get_tv; struct timezone timezone; struct tm *t; gettimeofday(&get_tv, &timezone); printf("stattv.tv_sec = %i\n", tv.tv_sec); printf("get_tv.tv_sec = %i\n", get_tv.tv_sec); */ return IoDate_newWithTimeval_(IOSTATE, tv); } IoObject *IoFile_userId(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("userId", "Returns a Number containing the user id associated with the file's path.") */ return IONUMBER(IoFile_statPointer(self, locals, m)->st_uid); } IoObject *IoFile_groupId(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("groupId", "Returns a Number containing the group id associated with the file's path.") */ return IONUMBER(IoFile_statPointer(self, locals, m)->st_gid); } IoObject *IoFile_statSize(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("statSize", "Returns the file's size in bytes as a Number.") */ return IONUMBER(IoFile_statPointer(self, locals, m)->st_size); } /* ---------------------------------- */ IoObject *IoFile_isDirectory(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("isDirectory", "Returns true if the receiver's path points to a directory, false otherwise.") */ return IOBOOL(self, S_ISDIR(IoFile_statPointer(self, locals, m)->st_mode)); } IoObject *IoFile_isPipe(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("isPipe", "Returns true if the receiver is a pipe, false otherwise.") */ return IOBOOL(self, S_ISFIFO(IoFile_statPointer(self, locals, m)->st_mode)); } IoObject *IoFile_isLink(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("isLink", "Returns true if the receiver's path points to a link, false otherwise.") */ struct stat buf; if (lstat(CSTRING(DATA(self)->path), &buf) != 0) { IoState_error_(IOSTATE, m, "unable to stat '%s': %s", CSTRING(DATA(self)->path), strerror(errno)); } return IOBOOL(self, S_ISLNK((&buf)->st_mode)); } IoObject *IoFile_isRegularFile(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("isRegularFile", "Returns true if the receiver's file descriptor is a regular file, false otherwise.") */ return IOBOOL(self, S_ISREG(IoFile_statPointer(self, locals, m)->st_mode)); } IoObject *IoFile_isSocket(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("isSocket", "Returns true if the receiver's file descriptor is a Socket, false otherwise.") */ return IOBOOL(self, S_ISSOCK(IoFile_statPointer(self, locals, m)->st_mode)); } IoObject *IoFile_isUserExecutable(IoFile *self, IoObject *locals, IoMessage *m) { /*#io docSlot("isUserExecutable", "Returns true if the receiver is user group executable, false otherwise.") */ #ifdef ON_WINDOWS return IOFALSE(self); #else mode_t mode = IoFile_statPointer(self, locals, m)->st_mode; mode_t check = S_IXUSR; return IOBOOL(self, mode & check); #endif }