NAME
SYNOPSIS
DESCRIPTION
The following options are available:
-a Append the output to the files rather than overwriting them.
-i Ignore the SIGINT signal.
The following operands are available:
file A pathname of an output file .
The tee utility takes the default action for all signals, except in the event of the -i option.
The tee utility exits 0 on success, and >0 if an error occurs.
STANDARDS
SEE ALSO
NAME
SYNOPSIS
DESCRIPTION
The time command can be used to cause a command to be timed no matter how much
CPU time it takes. For example:
% /bin/time cp /etc/rc /usr/bill/rc
0.1 real 0.0 user 0.0 sys
% /bin/time nroff sample1 > sample1.nroff
3.6 real 2.4 user 1.2 sys
This example indicates that the cp command used negligible amounts of user ( user ) and system time ( sys ), and had an elapsed time ( real ) of 1/10 second (0.1). The nroff command used 2.4 seconds of user time and 1.2 seconds of system time, and required 3.6 seconds of elapsed time.
RESTRICTIONS
NAME
SYNOPSIS
DESCRIPTION
In either string the notation 'a - b' denotes a range of characters from a to b in increasing ASCII order. The character \, followed by 1, 2 or 3 octal digits stands for the character whose ASCII code is given by those digits. As with the shell, the escape character \, followed by any other character, escapes any special meaning for that character.
When string2 is short, characters in string1 with no corresponding character in string2 are not translated.
In either string the following abbreviation conventions introduce ranges of characters or repeated characters into the strings.
[ a - z ]
Stands for the string of characters whose ASCII codes run from character a to character z, inclusive.
[ a * n ]
Stands for n repetitions of a. If the first digit of n is 0, n is considered octal; otherwise, n is taken to be decimal. A zero or missing n is taken to be huge; this facility is useful for padding string2.
OPTIONS
-c Complement the set of characters in string1 with respect to the universe of characters whose ASCII codes are 01 through 0377 octal;
-d Delete all input characters in string1.
-s Squeeze all strings of repeated output characters that are in string2 to single characters.
EXAMPLE
tr -cs A-Za-z '\012' < filename1 > filename2
SEE ALSO
BUGS
NAME
SYNOPSIS
DESCRIPTION
- Small and fast
- Handles many cat and sed formats
- Allows extraction of subdirectories
- Understands ./file type filenames
- Understands file continuation with >>
- Sorts file list by Subject: line
- Exits cleanly with CTRL-C
Unshar treats quotes and imbedded escape sequences intelligently and handles all the cat and sed formats the author ever seen, including sed commands which strip off more than one letter. There may be some formats it won't handle, but I've yet to find them.
Invoke unshar with as many archive filenames as you like. All the files in each archive will be extracted into the current directory. If a file already exists, unshar asks you how you want to handle it. Entering `Y' will overwrite the existing file with the version in the archive, `N' will skip past the file without extracting it, and `A' will overwrite this file and any other existing files without prompting you again. Including the -o flag on the command line causes files to always be overwritten.
OPERATION
When a shar archive contains a file for which a full pathname is given (as in source/file.c for example) unshar will create whatever directories are necessary. It also strips off leading /'s and ./'s, to make filenames understandable by GS/OS.
Occasionally, a shar file distribution will contain a file too large to fit into a single shar archive (archives are typically limited to around 60K or so for transmission over Usenet). One method some archivers use to get around this is to split the large file into several smaller parts, and use the shell `>>' redirection operator to concatenate the parts together while extracting the files. In order for this to work properly, it is important that the archive files are extracted in the correct sequence; otherwise, all the pieces will get joined together in the wrong order.
To assist with this, unshar does a prescan over all the files listed on the command line, and checks each file for a "Subject:" line. If it finds such a line, it scans it looking for any hints as to where the file comes in the sequence. Most shar files you feed to unshar will be directly from a Usenet sources or binaries group, and will include a volume and issue reference on the subject line. If unshar can't find such an issue reference, it will look for a Part number and use that instead.
Unshar then extracts the archives starting with the lowest numbered file. This helps to ensure that those extra-large files are created correctly. You can tell when such a file is being created, because unshar says "Extending file" rather than "Unsharing file".
If for some reason you want the files to be unarchived in the order listed on the command line, you can specify the `-n' (nosort) switch, and no sorting will take place.
HISTORY
V1.1 Added support for some more unusual uses of sed.
Increased speed, and reduced size slightly.
Fixed bug that truncated lines longer than 80 chars.
V1.2 Added support for sorting by Subject: line
Added support for file appending via >>
Fixed small bug in detection of disk write errors
AUTHOR
Apple //gs port by Andy McFadden (fadden@uts.amdahl.com).
NAME
SYNOPSIS
DESCRIPTION
OPTIONS
The default is -lwc (count lines, words, and characters).
-l Count lines.
-w Count words.
-c Count characters.
EXAMPLE
1876 11223 65895 /usr/share/man/man1/csh.1
674 3310 20338 /usr/share/man/man1/sh.1
260 1110 6834 /usr/share/man/man1/telnet.1
2810 15643 93067 total
example%
NAME
SYNOPSIS
DESCRIPTION
Without an argument, who examines the /etc/utmp file to obtain its information. If a file is given, that file is examined. Typically the given file will be /usr/adm/wtmp, which contains a record of all the logins since it was created. Then who lists logins, logouts, and crashes since the creation of the wtmp file. Each login is listed with user name, terminal name (with `/dev/' suppressed), and date and time. When an argument is given, logouts produce a similar line without a user name. Reboots produce a line with `x' in the place of the device name, and a fossil time indicative of when the system went down.
With two arguments, as in `who am I' (and also `who are you'), who tells who you are logged in as.
FILES
SEE ALSO
NAME
SYNOPSIS
DESCRIPTION
NAME
SYNOPSIS
long int alarm(long int seconds);
DESCRIPTION
When an alarm timer terminates (by counting down to 0), the calling process is sent a SIGALRM signal.
RETURN VALUE
SEE ALSO
NAME
SYNOPSIS
int dup(int filedes);
int dup2(int filedes, int filedes2);
DESCRIPTION
RETURN VALUE
[EBADF] filedes refers to an invalid file descriptor (not an open file)
[EMFILE] no more files can be opened; process is at current limit (32).
SEE ALSO
NAME
SYNOPSIS
int execve(char *pathname, char *cmdline);
DESCRIPTION
If the executable file does not contain an OMF Stack Segment (SEGKIND = $12), a default stack of 4096 bytes is allocated to the process. The direct-page pointer is set to the bottom of the stack memory (for C programs this is irrelevant).
The parameter cmdline is the list of arguments to be passed to the new process (a copy is actually passed). C programs parse cmdline automatically, and the individual pieces can be accessed through the argc/argv arguments to main(). cmdline can be accessed from assembly langugage through the X (high-order word of cmdline) and Y (low-order word) registers. However, if the executable file is of file type S16 ($B3), the cmdline argument is ignored and the X&Y registers are set to null (i.e. the command line is only passed to an EXE executable). The 8 characters "BYTEWRKS" are prepended to cmdline before being passed to the process (this is the same identifier used by the ORCA shell). This Shell Identifier distinguishes the GNO and ORCA environments from others that don't support the full range of shell calls, and can be accessed from C with the library function shellid(). The A register is set to the userID allocated for the process.
GS/OS prefixes 1 and 9 are set to the pathname of the directory containing the executable file; if the length of the path exceeds 64 characters prefix 1 is set to the null prefix (length 0).
The following information is inherited by the new executable: current machine state, controlling TTY, process group ID, and prefixes 0 and 8.
Caught signals are reset to the default action. Ignored signals remain ignored across the execve. Any signals in the parent's queue are not passed to the child, and the child is started with no signals blocked. The child inherits all the open files of its parent.
RETURN VALUE
[ENOENT] the pathname specified does not exist
[EIO] some general I/O error occurred trying to load the executable
BUGS
SEE ALSO
NAME
SYNOPSIS
int fork(void *addr);
DESCRIPTION
A the userID assigned to the process
X 0
Y 0
The child inherits the memory shadowing and machine state parameters of the parent, as well as signal blocking information and the ID of the controlling TTY. In addition, the child inherits all the open files of its parent.
A forked process may share code with other children or the parent. However, this is only allowed in a forward manner; any forked process that exits by function return will be terminated. Note that any shared global variables will need to be moderated with some type of mutual exclusion, either the kernel semaphore(2) routines or custom routines. This includes C stdio routines.
RETURN VALUE
[ENOMEM] not enough memory to create the new process
[EAGAIN] all process slots full; no more can be created
NOTES
CAVEATS
SEE ALSO
NAME
SYNOPSIS
int getpid(void);
int getpgrp(int pid);
int getppid(void);
DESCRIPTION
getpgrp returns the process group ID of the specified process, pid. This function is usually used when you wish to send a signal to all members of a process group using kill(2).
RETURN VALUE
getppid: The process ID of the caller's parent is returned. No errors are possible.
getpgrp: The process group ID of the specified process is returned. In the event of an error, getpgrp returns -1 and sets errno to the appropriate error code:
[ESRCH] pid is not a valid process ID
NOTES
SEE ALSO
NAME
getpgrp - get process group
SYNOPSIS
uid_t = getuid(void)
uid_t = geteuid(void)
gid_t = getgid(void)
gid_t = getegid(void)
DESCRIPTION
Getgid returns the real group ID of the current process, getegid the effective group ID. The real group ID is specified at login time. The effective group ID is more transient, and determines additional access permission during execution of a ``set-group-ID'' process, and it is for such processes that getgid is most useful.
NOTES
SEE ALSO
NAME
DESCRIPTION
Manual Page Command Syntax
name [- option ...] [ cmdarg ...]
where:
[] Surround an option or cmdarg that is not required.
... Indicates multiple occurrences of the option or cmdarg.
name The name of an executable file.
option (Almost always preceded by a "-".)
noargletter ... or,
argletter optarg [,...]
noargletter A single letter representing an option without an option-argument. Note that more than one noargletter option can be grouped after one "-".
argletter A single letter representing an option requiring an option-argument.
optarg An option-argument (character string) satisfying a preceding argletter. Note that groups of optargs following an argletter must be separated by white space and quoted.
cmdarg Path name (or other command argument) not beginning with a "-", or "-" by itself indicating the standard input.
SEE ALSO
NAME
SYNOPSIS
int ioctl(int fd, unsigned long request, void *argp)
DESCRIPTION
An ioctl request has encoded in it whether the argument is an "in" parameter or "out" parameter, and the size of the argument argp in bytes. Macros and defines used in specifying an ioctl request are located in the file <sys/ioctl.h>.
RETURN VALUE
ERRORS
[EBADF] Fd is not a valid descriptor.
[ENOTTY] Fd is not associated with a character special device.
[ENOTTY] The specified request does not apply to the kind of object that the descriptor fd references.
[EINVAL] Request or argp is not valid.
SEE ALSO
NAME
SYNOPSIS
int tcnewpgrp(int fdtty);
int settpgrp(int fdtty);
int tctpgrp(int fdtty, int pid);
DESCRIPTION
A process is suspended (stopped) if it performs a sufficiently invasive operation on a tty with a different process group. This includes these job control calls, reads from a terminal, and writes to a terminal if configured to do so with ioctl(2). When a tty file is first opened, it is assigned process group 0; init has process group 0. As init launches login processes on various ttys, it assigns process groups to those ttys and processes.
tcnewpgrp(fdtty): Allocates a new process group and assigns it to the terminal referred to by fdtty. If the calling process is not in the foreground, it is sent SIGTTOU.
settpgrp(fdtty): Sets the current process to have the same process group as fdtty.
tctpgrp(fdtty,pid): Sets the tty to the same process group as pid, where pid is the current process or a descendant of it.
RETURN VALUE
[EBADF] fdtty is not a valid file descriptor
[ENOTTY] fdtty does not refer to a terminal file
[ESRCH] pid is not a valid process identifier
NOTES
Forking a pipeline in a job-control shell: The shell starts with tcnewpgrp(fdtty), so that the tty is in the new process group before there are even any children. It then forks each process in the pipeline. Each process does settpgrp(fdtty), thus joining the new process group.
Handling a stopped child process: When the shell sees that a pipeline has stopped or exited, it does tctpgrp(fdtty,getpid()) to set the tty to its own process group. To resume the pipeline it does tctpgrp(fdtty,pid) where pid is one of the child processes, then sends SIGCONT.
Starting a process under a new tty: When, for instance, telnetd wants to grab a pseudo-tty, it opens the pty and forks a child process. The child does tcnewpgrp(fdtty) to give the tty a real process group, then settpgrp(fdtty) to place itself into the foreground.
Security under this scheme is trivial. There is no way a process can join a process group except by settpgrp(), and that requires a descriptor open to a tty with that pgrp. To make a tty have that pgrp requires either tcnewpgrp(), in which case nobody else is using the pgrp, or tctpgrp(), which reduces to the first problem of having a process in the process group. End of security proof. (Wasn't that easy?) Note that `using' must be defined as use both by ttys and by processes; the system keeps a table of pgrps, each with a total tty + process reference count. When the reference count reaches zero, the pgrp is automatically deallocated.
SEE ALSO
CREDITS
The GNO/ME implementation was written strictly from specs.
NAME
SYNOPSIS
int kill(int pid, int sig)
DESCRIPTION
sig can be a signal number, or it can be 0, in which case no signal is sent, but error checking is done (this can be used to verify a process ID). If sig has been blocked (sigblock(2)), the signal is deferred until it is unblocked, and kill returns immediately. Any previously pending signals of the same sig are lost (i.e. signals are not stacked).
If pid is 0, the signal is sent to all processes with the same process group ID as the caller, except for system processes.
Processes may signal themselves, in which case the signal handler is invoked immediately (if one is installed).
RETURN VALUE
[ESHRC] pid does not correspond to an existing process
[EINVAL] sig specifies an invalid signal number
SEE ALSO
BUGS
NAME
SYNOPSIS
int pipe(int filedes[2]);
DESCRIPTION
It is assumed that after the pipe has been set up, two (or more) cooperating processes (created by subsequent fork calls) will pass data through the pipe with Read and Write calls.
The shell has a syntax to set up a linear array of processes connected by pipes.
Read calls on an empty pipe (no buffered data) with only one end (all write file descriptors closed) returns an end-of-file.
A signal (SIGPIPE) is generated if a write on a pipe with only one end is attempted.
RETURN VALUE
ERRORS
[EMFILE] Too many descriptors are active.
[ENFILE] The system file table is full.
[EFAULT] The fildes buffer is in an invalid area of the process's address space.
SEE ALSO
BUGS
NOTES
NAME
SYNOPSIS
int swait(int sem);
int ssignal(int sem);
int screate(int count);
int sdelete(int sem);
DESCRIPTION
The initial count determines how many times swait can be called before processes are blocked. count must be >= 0, and is usually set to 1. screate returns a semaphore ID number as an integer. This ID must be used in all the other semaphore calls.
sdelete releases the specified semaphore, and returns all processes that were blocked to a ready state.
swait decrements the value of the semaphore (initially specified by count ) by 1. If the semaphore count is less than zero, the process is blocked and queued for release by ssignal.
ssignal increments the semaphore count by one. If the semaphore count is less than zero, ssignal releases arbitrarily a process that had been blocked; FIFO operation is not guaranteed.
RETURN VALUE
BUGS
HISTORY
NAME
SYNOPSIS
int setdebug(int options);
DESCRIPTION
dbgGSOS prints out the call numbers of any GS/OS or ORCA/shell calls that are made. The number is printed in hexadecimal format and is prefixed with a '$' character. For this and the other GS/OS call debug options, the entire call sequence is enclosed in parenthesis '()' to ease tracing multiple levels of calls.
dbgPATH If this flag is set, every time a filename argument to a GS/OS or shell call is fully expanded the expanded version is displayed as follows: "EP: <fullpath>".
dbgERROR For every GS/OS call that is made, if an error occurs the error code is printed in inverse lettering in hexidecimal format. The code is prefixed with a '#' to distinguish the error code from a call code on terminals that do not support inverse mode. If no error occurs on the call, no code is printed. This option has no effect unless dbgGSOS is also enabled.
dbgSIG This flag enables signal tracing. Each time a signal is sent, whether by kill(2), job control or keyboard, the signal number and target process is displayed. The format is: "kill (-signum): pid: tpid".
dbgSYSCALL The parameter lists to common system calls are displayed by this option flag. The actual format of the output varies from call to call. The calls that currently support this flag are execve(2), fork(2), and the job control routines.
dbgPBLOCK The memory address of GS/OS and Shell parameter blocks is printed for each call. As with dbgERROR, this option has no effect unless dbgGSOS is also enabled.
RETURN VALUE
SEE ALSO
BUGS
NAME
SYNOPSIS
long sigblock(long mask);
#define sigmask(signum)
DESCRIPTION
sigmask is a macro that can be used to calculate signal masks for sigblock. It takes a signal number (signum) as an argument and returns a mask that can then be passed to sigblock.
If a signal is sent to a process but is blocked, the event is recorded for later release by sigsetmask(2). Blocked signals are not stacked; further occurrences of a blocked signal will overwrite any previous pending signal of the same signum.
It is not possible to block SIGKILL, SIGCONT, or SIGSTOP. This restriction is silently enforced by the system.
RETURN VALUE
SEE ALSO
NAME
SYNOPSIS
void (*signal(int sig; void (*func(void))(void)
DESCRIPTION
Most signals cause termination, unless a handler is installed, or the signal is set to be ignored. Certain signals cannot have their default action modified; the system silently enforces this restriction. The following is a list of signals and default actions (taken from signal.h).
SIGHUP 1 hangup
SIGINT 2 interrupt
SIGQUIT 3 quit
SIGILL 4 illegal instruction
SIGTRAP 5 trace trap
SIGABRT 6 abort (generated by abort(3) routine)
SIGEMT 7 emulator trap
SIGFPE 8 arithmetic exception
SIGKILL 9 kill (cannot be caught, blocked, or ignored)
SIGBUS 10 bus error
SIGSEGV 11 segmentation violation
SIGSYS 12 bad argument to system call
SIGPIPE 13 write on a pipe or other socket with no one to read it
SIGALRM 14 alarm clock
SIGTERM 15 software termination signal
SIGURG 16@ urgent condition present on socket
SIGSTOP 17 | + stop (cannot be caught, blocked, or ignored)
SIGTSTP 18 | + stop signal generated from keyboard
SIGCONT 19@ continue after stop (cannot be blocked)
SIGCHLD 20@ child status has changed
SIGCLD 20 System V name for SIGCHLD
SIGTTIN 21 | + background read attempted from control terminal
SIGTTOU 22 | + background write attempted to control terminal
SIGIO 23@ input/output possible on a file descriptor
SIGPOLL SIGIO System V name for SIGIO
SIGXCPU 24 exceeded CPU time limit
SIGUSR1 30 user defined signal 1
SIGUSR2 31 user defined signal 2
If func is SIG_DFL, the defult action for the signal is reinstalled. This is normally termination if the signal isn't ignored or caught. Signals marked with an @ are discarded, and signals marked with | + cause the process to stop. If func is SIG_IGN, any future occurences of the signal are discarded, as well as any pending instances. Any other value is treated as the address of a handler routine. The system will block further occurences of the signal before the handler is called, and will unblock the signal automatically upon return from the handler. The handler remains installed after return, unlike earlier UNIX signal facilities.
If a signal occurs during certain system calls (wait(), and input from a TTY), the call is automatically restarted upon return from the handler.
A forked child inherits all signal information, including pending signals and blocking and handler information. exec() and execve() restore all signal information to defaults and purge pending signals.
NOTES
void handler (int sig, int code)
sig is the signal that invoked the handler, and code is additional information about the interrupt condition. Currently, code is always 0. The handler should probably also be compiled using the #pragma databank 1 directive, in the event the signal handler is not in the same bank as the C global data segment (the handler is called with the data bank equal to the program bank).
RETURN VALUE
sig specifies an invalid signal number.
An attempt is made to ignore or supply a handler for SIGKILL or SIGSTOP.
An attempt is made to ignore SIGCONT (by default SIGCONT is ignored).
CAVEATS
SEE ALSO
NAME
SYNOPSIS
int sigpause(long int mask);
DESCRIPTION
sigpause is normally used in situations where one must protect a critical section. A typical use begins with sigblock to block a signal (and enable mutual exclusion); variables modified on the occurrence of that signal are then manipulated, code is executed, etc. To end the critical section and wait for more work, sigpuase is called.
RETURN VALUE
SEE ALSO
NAME
SYNOPSIS
long sigsetmask(long mask);
#define sigmask(signum)
DESCRIPTION
If there are pending instances of signals which become unblocked by the sigsetmask call, they are 'released' into the system signal queue and their 'pending' status is cleared. The system signal queue is maintained by the kernel null process, and is used in situations where signals could not normally be sent (such as interrupt handlers).
sigmask is a macro that can be used to calculate signal masks for sigsetmask. It takes a signal number, as listed in signal(2), as an argument and returns a mask corresponding to that signal.
RETURN VALUE
CAVEATS
SEE ALSO
NAME
SYNOPSIS
int stat(const char *filename, struct stat *s_buf);
int fstat(int filedes, struct stat *s_buf);
int lstat(const char *filename, struct stat *s_buf);
DESCRIPTION
stat takes arguments filename, a NUL-terminated string naming the file to get information on, and s_buf, a pointer to a stat structure, defined in <sys/stat.h>. filename can be a partial or a complete path. The miscellaneous types in struct stat, below, are defined in <sys/types.h>, automatically included by stat.h.
struct stat {
dev_t st_dev; /* ID number of device file resides on */
ino_t st_ino; /* inode number of file */
unsigned short st_mode; /* type of file and mode */
short st_nlink; /* number of links to file = 0 */
uid_t st_uid; /* user id = 0 */
gid_t st_gid; /* group id = 0 */
dev_t st_rdev; /* device type ID */
off_t st_size; /* length of file in bytes */
time_t st_atime; /* last access time (same as mod time on Apple IIGS) */
int st_spare1; /* reserved */
time_t st_mtime; /* last modification time */
int st_spare2; /* reserved */
time_t st_ctime; /* file creation time */
int st_spare3; /* reserved */
long st_blksize; /* size in bytes of blocks on filesystem */
long st_blocks; /* number of blocks file uses */
long st_spare4[2]; /* reserved */
};
The items marked 'reserved' are not currently used but are reserved for future expansion; do not use these fields for any reason. st_dev is the device number the file resides on. This number is the same as the GS/OS device ID number. st_rdev is not currently used, but may in the future designate a device type code.
st_mode is a bit field representing access mode and type of the file. The flags in st_mode are as follows:
#define S_IFDIR 0040000 /* directory */
#define S_IFCHR 0020000 /* character special */
#define S_IFBLK 0060000 /* block special */
#define S_IFREG 0100000 /* regular */
#define S_IFLNK 0120000 /* symbolic link */
#define S_IFSOCK 0140000 /* socket or pipe */
#define S_IREAD 0000400 /* read permission, owner */
#define S_IWRITE 0000200 /* write permission, owner */
#define S_IEXEC 0000100 /* file is an executable, owner */
fstat is similar to stat except the argument is an open file descriptor filedes. If filedes refers to a character device or pipe, the entire s_buf is set to 0 and only st_mode and st_dev are set.
lstat is similar to stat, but if the filename is a link then information is returned about the link file instead of the file linked to.
RETURN VALUE
[ENOENT] filename does not specify an existing file or directory
[ENOTDIR] an element of filename is not an expected subdirectory
fstat can additionally return
[EBADF] filedes does not refer to an open file descriptor
BUGS
fstat doesn't do anything clever with all the unused fields in struct stat when its argument is a pipe or terminal.
NAME
SYNOPSIS
int statfs(char *path, struct statfs *buf)
int fstatfs(int fd, struct statfs *buf)
DESCRIPTION
typedef struct {
long val[2];
} fsid_t;
struct statfs {
long f_type; /* type of info, zero for now */
long f_bsize; /* fundamental file system block size */
long f_blocks; /* total blocks in file system */
long f_bfree; /* free blocks */
long f_bavail; /* free blocks available to non-superuser */
long f_files; /* total file nodes in file system */
long f_ffree; /* free file nodes in fs */
fsid_t f_fsid; /* file system id */
long f_spare[7]; /* spare for later */
};
Fields that are undefined for a particular file system are set to -1. fstatfs returns the same information about an open file referenced by descriptor fd.
RETURN VALUE
ERRORS
ENOTDIR A component of the path prefix of path is not a directory.
EINVAL path contains a character with the high-order bit set.
ENAMETOOLONG The length of a component of path exceeds 255 characters, or the length of path exceeds 1023 characters.
ENOENT The file referred to by path does not exist.
EACCES Search permission is denied for a component of the path prefix of path.
EIO An I/O error occurred while reading from or writing to the file system.
fstatfs fails if one or both of the following are true:
EBADF fd is not a valid open file descriptor.
EIO An I/O error occurred while reading from or writing to the file system