static void try___getcwd(int dofork) { void * a0 = randptr(); size_t a1 = randsize(); int result, pid, status; char buf[128]; snprintf(buf, sizeof(buf), "__getcwd(%p, %lu)", (a0), (unsigned long)(a1)); printf("%-47s", buf); pid = dofork ? fork() : 0; if (pid<0) { err(1, "fork"); } if (pid>0) { waitpid(pid, &status, 0); return; } result = __getcwd(a0, a1); printf(" result %d, errno %d\n", result, errno); if (dofork) { exit(0); } }
char * __getwd_chk (char *buf, size_t buflen) { char *res = __getcwd (buf, buflen); if (res == NULL && errno == ERANGE) __chk_fail (); return res; }
char * __getcwd_chk (char *buf, size_t size, size_t buflen) { if (size > buflen) __chk_fail (); return __getcwd (buf, size); }
// Returns the current directory std::string GetCurrentDir() { char *dir; // Get the current working directory (getcwd uses malloc) if (!(dir = __getcwd(NULL, 0))) { LOG_ERROR(TCOMMON, "GetCurrentDirectory failed:"); return NULL; } std::string strDir = dir; free(dir); return strDir; }
// Returns the current directory std::string GetCurrentDir() { // Get the current working directory (getcwd uses malloc) char* dir = __getcwd(nullptr, 0); if (!dir) { ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", GetLastErrorMsg().c_str()); return nullptr; } std::string strDir = dir; free(dir); return strDir; }
// Returns the current directory std::string GetCurrentDir() { char *dir; // Get the current working directory (getcwd uses malloc) if (!(dir = __getcwd(NULL, 0))) { ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", GetLastErrorMsg()); return NULL; } std::string strDir = dir; free(dir); return strDir; }
// Returns the current directory std::string GetCurrentDir() { char *dir; // Get the current working directory (getcwd uses malloc) if (!(dir = __getcwd(nullptr, 0))) { LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s", GetLastErrorMsg()); return nullptr; } std::string strDir = dir; free(dir); return strDir; }
int main(int argc, char *argv[]) { (void)argc; (void)argv; char buf[128]; if(__getcwd(buf, sizeof(buf)-1)){ printf("getcwd err: %d\n", errno); } printf("Initial directory: %s\n", buf); if (chdir("testdir") != 0) printf("chdir failed: %d\n", errno); printf("success!\n"); if(__getcwd(buf, sizeof(buf)-1)){ printf("getcwd err: %d\n", errno); } printf("Changed directory: %s\n", buf); return 0; }
char * get_current_dir_name (void) { char *pwd; struct stat64 dotstat, pwdstat; pwd = getenv ("PWD"); if (pwd != NULL && stat64 (".", &dotstat) == 0 && stat64 (pwd, &pwdstat) == 0 && pwdstat.st_dev == dotstat.st_dev && pwdstat.st_ino == dotstat.st_ino) /* The PWD value is correct. Use it. */ return __strdup (pwd); return __getcwd ((char *) NULL, 0); }
char* getwd (char *buf) { char mybuf[PATH_MAX]; if (buf == NULL) { __set_errno (EINVAL); return NULL; } if (__getcwd (mybuf, PATH_MAX) == NULL) { __strerror_r (errno, buf, PATH_MAX); return NULL; } return strcpy (buf, mybuf); /* Ouch. */ }
char * getcwd(char *buf, size_t size) { char *allocated = NULL; if (buf != NULL && size == 0) { errno = EINVAL; return (NULL); } if (buf == NULL && (allocated = buf = malloc(size = PATH_MAX)) == NULL) return (NULL); if (__getcwd(buf, size) == -1) { free(allocated); return (NULL); } return (buf); }
char * getcwd(char *pt, size_t size) { int allocated = 0, ret; /* * If no buffer specified by the user, allocate one as necessary. */ if (pt == NULL) { size = MAXPATHLEN; if ((pt = malloc(MAXPATHLEN)) == NULL) return(NULL); allocated = 1; } ret = __getcwd(pt, size); if (ret == 0) return (pt); if (allocated) free(pt); return (NULL); }
char * __realpath (const char *name, char *resolved) { char *rpath, *dest, *extra_buf = NULL; const char *start, *end, *rpath_limit; long int path_max; int num_links = 0; size_t prefix_len; if (name == NULL) { /* As per Single Unix Specification V2 we must return an error if either parameter is a null pointer. We extend this to allow the RESOLVED parameter to be NULL in case the we are expected to allocate the room for the return value. */ __set_errno (EINVAL); return NULL; } if (name[0] == '\0') { /* As per Single Unix Specification V2 we must return an error if the name argument points to an empty string. */ __set_errno (ENOENT); return NULL; } #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf (name, _PC_PATH_MAX); if (path_max <= 0) path_max = 8192; #endif if (resolved == NULL) { rpath = malloc (path_max); if (rpath == NULL) { /* It's easier to set errno to ENOMEM than to rely on the 'malloc-posix' gnulib module. */ errno = ENOMEM; return NULL; } } else rpath = resolved; rpath_limit = rpath + path_max; /* This is always zero for Posix hosts, but can be 2 for MS-Windows and MS-DOS X:/foo/bar file names. */ prefix_len = FILE_SYSTEM_PREFIX_LEN (name); if (!IS_ABSOLUTE_FILE_NAME (name)) { if (!__getcwd (rpath, path_max)) { rpath[0] = '\0'; goto error; } dest = strchr (rpath, '\0'); start = name; prefix_len = FILE_SYSTEM_PREFIX_LEN (rpath); } else { dest = rpath; if (prefix_len) { memcpy (rpath, name, prefix_len); dest += prefix_len; } *dest++ = '/'; if (DOUBLE_SLASH_IS_DISTINCT_ROOT) { if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len) *dest++ = '/'; *dest = '\0'; } start = name + prefix_len; } for (end = start; *start; start = end) { #ifdef _LIBC struct stat64 st; #else struct stat st; #endif int n; /* Skip sequence of multiple path-separators. */ while (ISSLASH (*start)) ++start; /* Find end of path component. */ for (end = start; *end && !ISSLASH (*end); ++end) /* Nothing. */; if (end - start == 0) break; else if (end - start == 1 && start[0] == '.') /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') { /* Back up to previous component, ignore if at root already. */ if (dest > rpath + prefix_len + 1) for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest) continue; if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1])) dest++; } else { size_t new_size; if (!ISSLASH (dest[-1])) *dest++ = '/'; if (dest + (end - start) >= rpath_limit) { ptrdiff_t dest_offset = dest - rpath; char *new_rpath; if (resolved) { __set_errno (ENAMETOOLONG); if (dest > rpath + prefix_len + 1) dest--; *dest = '\0'; goto error; } new_size = rpath_limit - rpath; if (end - start + 1 > path_max) new_size += end - start + 1; else new_size += path_max; new_rpath = (char *) realloc (rpath, new_size); if (new_rpath == NULL) { /* It's easier to set errno to ENOMEM than to rely on the 'realloc-posix' gnulib module. */ errno = ENOMEM; goto error; } rpath = new_rpath; rpath_limit = rpath + new_size; dest = rpath + dest_offset; } #ifdef _LIBC dest = __mempcpy (dest, start, end - start); #else memcpy (dest, start, end - start); dest += end - start; #endif *dest = '\0'; #ifdef _LIBC if (__lxstat64 (_STAT_VER, rpath, &st) < 0) #else if (lstat (rpath, &st) < 0) #endif goto error; if (S_ISLNK (st.st_mode)) { char *buf; size_t len; if (++num_links > MAXSYMLINKS) { __set_errno (ELOOP); goto error; } buf = malloca (path_max); if (!buf) { errno = ENOMEM; goto error; } n = __readlink (rpath, buf, path_max - 1); if (n < 0) { int saved_errno = errno; freea (buf); errno = saved_errno; goto error; } buf[n] = '\0'; if (!extra_buf) { extra_buf = malloca (path_max); if (!extra_buf) { freea (buf); errno = ENOMEM; goto error; } } len = strlen (end); if ((long int) (n + len) >= path_max) { freea (buf); __set_errno (ENAMETOOLONG); goto error; } /* Careful here, end may be a pointer into extra_buf... */ memmove (&extra_buf[n], end, len + 1); name = end = memcpy (extra_buf, buf, n); if (IS_ABSOLUTE_FILE_NAME (buf)) { size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf); if (pfxlen) memcpy (rpath, buf, pfxlen); dest = rpath + pfxlen; *dest++ = '/'; /* It's an absolute symlink */ if (DOUBLE_SLASH_IS_DISTINCT_ROOT) { if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen) *dest++ = '/'; *dest = '\0'; } /* Install the new prefix to be in effect hereafter. */ prefix_len = pfxlen; } else { /* Back up to previous component, ignore if at root already: */ if (dest > rpath + prefix_len + 1) for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest) continue; if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len) dest++; } } else if (!S_ISDIR (st.st_mode) && *end != '\0') { __set_errno (ENOTDIR); goto error; } } } if (dest > rpath + prefix_len + 1 && ISSLASH (dest[-1])) --dest; if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1])) dest++; *dest = '\0'; if (extra_buf) freea (extra_buf); return rpath; error: { int saved_errno = errno; if (extra_buf) freea (extra_buf); if (resolved == NULL) free (rpath); errno = saved_errno; } return NULL; }
void mips_syscall(struct trapframe *tf) { int callno; int32_t retval; int err; assert(curspl==0); callno = tf->tf_v0; /* * Initialize retval to 0. Many of the system calls don't * really return a value, just 0 for success and -1 on * error. Since retval is the value returned on success, * initialize it to 0 by default; thus it's not necessary to * deal with it except for calls that return other values, * like write. * fk: we also initialize err to be 0 (no error by default) */ retval = 0; err = 0; // -- fk -- switch (callno) { case SYS_reboot: err = sys_reboot(tf->tf_a0); break; /* Add stuff here */ // --- fk --- case SYS_open: retval = open(tf->tf_a0, tf->tf_a1); break; case SYS_read: retval = read(tf->tf_a0, tf->tf_a1, tf->tf_a2); break; case SYS_write: retval = write(tf->tf_a0, tf->tf_a1, tf->tf_a2); break; case SYS_close: retval = close(tf->tf_a0); break; case SYS_lseek: retval = lseek(tf->tf_a0, tf->tf_a1, tf->tf_a2); break; case SYS_chdir: retval = chdir(tf->tf_a0); break; case SYS___getcwd: retval = __getcwd(tf->tf_a0, tf->tf_a1); break; case SYS_dup2: retval = dup2(tf->tf_a0, tf->tf_a1); break; // --- /fk --- default: kprintf("Unknown syscall %d\n", callno); err = ENOSYS; break; } // --- fk --- if (retval == -1){ err = file_errno; } // --- /fk --- if (err) { /* * Return the error code. This gets converted at * userlevel to a return value of -1 and the error * code in errno. */ tf->tf_v0 = err; tf->tf_a3 = 1; /* signal an error */ } else { /* Success. */ tf->tf_v0 = retval; tf->tf_a3 = 0; /* signal no error */ } /* * Now, advance the program counter, to avoid restarting * the syscall over and over again. */ tf->tf_epc += 4; /* Make sure the syscall code didn't forget to lower spl */ assert(curspl==0); }
bool Process::start() { #ifdef WIN32 handle_IN_Rd = NULL; handle_IN_Wr = NULL; handle_OUT_Rd = NULL; handle_OUT_Wr = NULL; handle_ERR_Rd = NULL; handle_ERR_Wr = NULL; p_stdin = -1; p_stdout = -1; p_stderr = -1; SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // Create a pipe for the child process's STDOUT. if ( ! CreatePipe(&handle_OUT_Rd, &handle_OUT_Wr, &saAttr, 0) ) return false; // Create a pipe for the child process's STDERR. if ( ! CreatePipe(&handle_ERR_Rd, &handle_ERR_Wr, &saAttr, 0) ) return false; // Create a pipe for the child process's STDIN. if (! CreatePipe(&handle_IN_Rd, &handle_IN_Wr, &saAttr, 0)) return false; if (explicit_mode) { if ( ! SetHandleInformation(handle_IN_Rd, HANDLE_FLAG_INHERIT, 1) ) return false; if ( ! SetHandleInformation(handle_OUT_Wr, HANDLE_FLAG_INHERIT, 1) ) return false; } // Ensure the write handle to the pipe for STDIN is not inherited. if ( ! SetHandleInformation(handle_IN_Wr, HANDLE_FLAG_INHERIT, 0) ) return false; // Ensure the read handle to the pipe for STDOUT is not inherited. if ( ! SetHandleInformation(handle_OUT_Rd, HANDLE_FLAG_INHERIT, 0) ) return false; // Ensure the read handle to the pipe for STDERR is not inherited. if ( ! SetHandleInformation(handle_ERR_Rd, HANDLE_FLAG_INHERIT, 0) ) return false; STARTUPINFO siStartInfo; BOOL bSuccess = FALSE; // Set up members of the PROCESS_INFORMATION structure. ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); stringstream cmdbuffer; int curargument = 0; while (arguments[curargument]) { cmdbuffer << "\"" << arguments[curargument] << "\" "; curargument++; } stringstream envbuffer; map<string, string>::iterator iter; for (iter = env.begin(); iter != env.end(); ++iter) { envbuffer << iter->first << string("=") << iter->second << '\0'; } // Set up members of the STARTUPINFO structure. // This structure specifies the STDIN and STDOUT handles for redirection. ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); siStartInfo.cb = sizeof(STARTUPINFO); if (!explicit_mode) { siStartInfo.hStdError = handle_ERR_Wr; siStartInfo.hStdOutput = handle_OUT_Wr; siStartInfo.hStdInput = handle_IN_Rd; siStartInfo.dwFlags |= STARTF_USESTDHANDLES; } else { siStartInfo.hStdError = handle_ERR_Wr; HANDLE pHandle = GetCurrentProcess(); HANDLE handle_IN_Rd2, handle_OUT_Wr2; DuplicateHandle(pHandle, handle_IN_Rd, pHandle, &handle_IN_Rd2, DUPLICATE_SAME_ACCESS, true, DUPLICATE_SAME_ACCESS); DuplicateHandle(pHandle, handle_OUT_Wr, pHandle, &handle_OUT_Wr2, DUPLICATE_SAME_ACCESS, true, DUPLICATE_SAME_ACCESS); envbuffer << string("TRAX_IN=") << handle_IN_Rd2 << '\0'; envbuffer << string("TRAX_OUT=") << handle_OUT_Wr2 << '\0'; } envbuffer << '\0'; LPCSTR curdir = directory.empty() ? NULL : directory.c_str(); if (!CreateProcess(NULL, (char *) cmdbuffer.str().c_str(), NULL, NULL, true, 0, (void *)envbuffer.str().c_str(), curdir, &siStartInfo, &piProcInfo )) { std::cout << "Error: " << GetLastError() << std::endl; cleanup(); return false; } int wrfd = _open_osfhandle((intptr_t)handle_IN_Wr, 0); int rdfd = _open_osfhandle((intptr_t)handle_OUT_Rd, _O_RDONLY); int erfd = _open_osfhandle((intptr_t)handle_ERR_Rd, _O_RDONLY); if (wrfd == -1 || rdfd == -1) { stop(); return false; } p_stdin = wrfd; p_stdout = rdfd; p_stderr = erfd; if (!p_stdin || !p_stdout) { stop(); return false; } #else if (pid) return false; pipe(out); pipe(in); pipe(err); vector<string> vars; map<string, string>::iterator iter; for (iter = env.begin(); iter != env.end(); ++iter) { // if (iter->first == "PWD") continue; vars.push_back(iter->first + string("=") + iter->second); } posix_spawn_file_actions_init(&action); posix_spawn_file_actions_addclose(&action, out[1]); posix_spawn_file_actions_addclose(&action, in[0]); posix_spawn_file_actions_addclose(&action, err[0]); if (!explicit_mode) { posix_spawn_file_actions_adddup2(&action, out[0], 0); posix_spawn_file_actions_adddup2(&action, in[1], 1); posix_spawn_file_actions_adddup2(&action, err[1], 2); } else { posix_spawn_file_actions_adddup2(&action, err[1], 2); vars.push_back(string("TRAX_OUT=") + int_to_string(in[1])); vars.push_back(string("TRAX_IN=") + int_to_string(out[0])); } std::vector<char *> vars_c(vars.size() + 1); for (std::size_t i = 0; i != vars.size(); ++i) { vars_c[i] = &vars[i][0]; } vars_c[vars.size()] = NULL; string cwd = __getcwd(); if (directory.size() > 0) chdir(directory.c_str()); if (posix_spawnp(&pid, program, &action, NULL, arguments, vars_c.data())) { cleanup(); pid = 0; if (directory.size() > 0) chdir(cwd.c_str()); return false; } if (directory.size() > 0) chdir(cwd.c_str()); p_stdin = out[1]; p_stdout = in[0]; p_stderr = err[0]; #endif return true; }
ftw_startup (const char *dir, int is_nftw, void *func, int descriptors, int flags) { struct ftw_data data; struct STAT st; int result = 0; int save_err; int cwdfd = -1; char *cwd = NULL; char *cp; /* First make sure the parameters are reasonable. */ if (dir[0] == '\0') { __set_errno (ENOENT); return -1; } data.maxdir = descriptors < 1 ? 1 : descriptors; data.actdir = 0; data.dirstreams = (struct dir_data **) alloca (data.maxdir * sizeof (struct dir_data *)); memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *)); /* PATH_MAX is always defined when we get here. */ data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX); data.dirbuf = (char *) malloc (data.dirbufsize); if (data.dirbuf == NULL) return -1; cp = __stpcpy (data.dirbuf, dir); /* Strip trailing slashes. */ while (cp > data.dirbuf + 1 && cp[-1] == '/') --cp; *cp = '\0'; data.ftw.level = 0; /* Find basename. */ while (cp > data.dirbuf && cp[-1] != '/') --cp; data.ftw.base = cp - data.dirbuf; data.flags = flags; /* This assignment might seem to be strange but it is what we want. The trick is that the first three arguments to the `ftw' and `nftw' callback functions are equal. Therefore we can call in every case the callback using the format of the `nftw' version and get the correct result since the stack layout for a function call in C allows this. */ data.func = (NFTW_FUNC_T) func; /* Since we internally use the complete set of FTW_* values we need to reduce the value range before calling a `ftw' callback. */ data.cvt_arr = is_nftw ? nftw_arr : ftw_arr; /* No object known so far. */ data.known_objects = NULL; /* Now go to the directory containing the initial file/directory. */ if (flags & FTW_CHDIR) { /* We have to be able to go back to the current working directory. The best way to do this is to use a file descriptor. */ cwdfd = __open (".", O_RDONLY | O_DIRECTORY); if (cwdfd == -1) { /* Try getting the directory name. This can be needed if the current directory is executable but not readable. */ if (errno == EACCES) /* GNU extension ahead. */ cwd = __getcwd (NULL, 0); if (cwd == NULL) goto out_fail; } else if (data.maxdir > 1) /* Account for the file descriptor we use here. */ --data.maxdir; if (data.ftw.base > 0) { /* Change to the directory the file is in. In data.dirbuf we have a writable copy of the file name. Just NUL terminate it for now and change the directory. */ if (data.ftw.base == 1) /* I.e., the file is in the root directory. */ result = __chdir ("/"); else { char ch = data.dirbuf[data.ftw.base - 1]; data.dirbuf[data.ftw.base - 1] = '\0'; result = __chdir (data.dirbuf); data.dirbuf[data.ftw.base - 1] = ch; } } } /* Get stat info for start directory. */ if (result == 0) { const char *name; if (data.flags & FTW_CHDIR) { name = data.dirbuf + data.ftw.base; if (name[0] == '\0') name = "."; } else name = data.dirbuf; if (((flags & FTW_PHYS) ? LXSTAT (_STAT_VER, name, &st) : XSTAT (_STAT_VER, name, &st)) < 0) { if (!(flags & FTW_PHYS) && errno == ENOENT && LXSTAT (_STAT_VER, name, &st) == 0 && S_ISLNK (st.st_mode)) result = (*data.func) (data.dirbuf, &st, data.cvt_arr[FTW_SLN], &data.ftw); else /* No need to call the callback since we cannot say anything about the object. */ result = -1; } else { if (S_ISDIR (st.st_mode)) { /* Remember the device of the initial directory in case FTW_MOUNT is given. */ data.dev = st.st_dev; /* We know this directory now. */ if (!(flags & FTW_PHYS)) result = add_object (&data, &st); if (result == 0) result = ftw_dir (&data, &st, NULL); } else { int flag = S_ISLNK (st.st_mode) ? FTW_SL : FTW_F; result = (*data.func) (data.dirbuf, &st, data.cvt_arr[flag], &data.ftw); } } if ((flags & FTW_ACTIONRETVAL) && (result == FTW_SKIP_SUBTREE || result == FTW_SKIP_SIBLINGS)) result = 0; } /* Return to the start directory (if necessary). */ if (cwdfd != -1) { int save_err = errno; __fchdir (cwdfd); __close_nocancel_nostatus (cwdfd); __set_errno (save_err); } else if (cwd != NULL) { int save_err = errno; __chdir (cwd); free (cwd); __set_errno (save_err); } /* Free all memory. */ out_fail: save_err = errno; __tdestroy (data.known_objects, free); free (data.dirbuf); __set_errno (save_err); return result; }
static char *canonicalize (const char *name) { char *rpath, *dest, *extra_buf = NULL; const char *start, *end, *rpath_limit; long int path_max; int num_links = 0, err = 0; if (name == NULL) { /* As per Single Unix Specification V2 we must return an error if either parameter is a null pointer. We extend this to allow the RESOLVED parameter be NULL in case the we are expected to allocate the room for the return value. */ __set_errno (EINVAL); return NULL; } if (name[0] == '\0') { /* As per Single Unix Specification V2 we must return an error if the name argument points to an empty string. */ __set_errno (ENOENT); return NULL; } #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf (name, _PC_PATH_MAX); if (path_max <= 0) path_max = 1024; #endif rpath = (char *) __alloca (path_max); rpath_limit = rpath + path_max; if (name[0] != '/') { if (!__getcwd (rpath, path_max)) goto error; dest = strchr (rpath, '\0'); } else { rpath[0] = '/'; dest = rpath + 1; } for (start = end = name; *start; start = end) { struct stat st; int n; /* Skip sequence of multiple path-separators. */ while (*start == '/') ++start; /* Find end of path component. */ for (end = start; *end && *end != '/'; ++end) /* Nothing. */; if (end - start == 0) break; else if (end - start == 1 && start[0] == '.') /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') { /* Back up to previous component, ignore if at root already. */ if (dest > rpath + 1) while ((--dest)[-1] != '/'); } else { if (dest[-1] != '/') *dest++ = '/'; if (dest + (end - start) >= rpath_limit) { __set_errno (ENAMETOOLONG); goto error; } memmove(dest, start, end - start); dest = (char *) dest + (end - start); *dest = '\0'; /* let's try changing the semantic to always ignore * underlying filesystem if path so far is in capfstab file. * That way we don't get silly kernel errors when using the * library. This is easy - just move (well, just copy for * now) the search_fstab check to here. If you get a match, * increment err. err doesn't actually signal a fatal error, * just causes it to quit getting at underlying * filesystem. -- don * */ if (search_fstab(rpath)) { /* rpath is in the capfstab */ err++; } /* we used to crap out in this case; now we simply note that we * hit an error and stop trying to stat from now on. -- Rob */ if (!err && __lxstat (_STAT_VER, rpath, &st) < 0) { err++; } if (!err && (S_ISLNK (st.st_mode))) { char *buf = (char *) __alloca (path_max); size_t len; if (++num_links > MAXSYMLINKS) { __set_errno (ELOOP); goto error; } n = __readlink (rpath, buf, path_max); if (n < 0) goto error; buf[n] = '\0'; if (!extra_buf) extra_buf = (char *) __alloca (path_max); len = strlen (end); if ((long int) (n + len) >= path_max) { __set_errno (ENAMETOOLONG); goto error; } /* Careful here, end may be a pointer into extra_buf... */ memmove (&extra_buf[n], end, len + 1); name = end = memcpy (extra_buf, buf, n); if (buf[0] == '/') dest = rpath + 1; /* It's an absolute symlink */ else /* Back up to previous component, ignore if at root already: */ if (dest > rpath + 1) while ((--dest)[-1] != '/'); } } } if (dest > rpath + 1 && dest[-1] == '/') --dest; *dest = '\0'; memcpy(canonicalize_outbuf, rpath, dest - rpath + 1); return(canonicalize_outbuf); error: /* copy in component causing trouble */ strcpy (canonicalize_outbuf, rpath); return(canonicalize_outbuf); }
/* * System call dispatcher. * * A pointer to the trapframe created during exception entry (in * exception-*.S) is passed in. * * The calling conventions for syscalls are as follows: Like ordinary * function calls, the first 4 32-bit arguments are passed in the 4 * argument registers a0-a3. 64-bit arguments are passed in *aligned* * pairs of registers, that is, either a0/a1 or a2/a3. This means that * if the first argument is 32-bit and the second is 64-bit, a1 is * unused. * * This much is the same as the calling conventions for ordinary * function calls. In addition, the system call number is passed in * the v0 register. * * On successful return, the return value is passed back in the v0 * register, or v0 and v1 if 64-bit. This is also like an ordinary * function call, and additionally the a3 register is also set to 0 to * indicate success. * * On an error return, the error code is passed back in the v0 * register, and the a3 register is set to 1 to indicate failure. * (Userlevel code takes care of storing the error code in errno and * returning the value -1 from the actual userlevel syscall function. * See src/user/lib/libc/arch/mips/syscalls-mips.S and related files.) * * Upon syscall return the program counter stored in the trapframe * must be incremented by one instruction; otherwise the exception * return code will restart the "syscall" instruction and the system * call will repeat forever. * * If you run out of registers (which happens quickly with 64-bit * values) further arguments must be fetched from the user-level * stack, starting at sp+16 to skip over the slots for the * registerized values, with copyin(). */ void syscall(void *trapframe, unsigned long junk) { curproc->rt = (curproc->rt == BACKGROUND_U ? BACKGROUND_K : INTERACTIVE_K); (void)junk; struct trapframe *tf = (struct trapframe*)trapframe; if(!curproc->context) curproc->context = kmalloc(sizeof(struct trapframe)); memcpy(curproc->context, tf, sizeof(struct trapframe)); int callno; int32_t retval; int err; KASSERT(curthread != NULL); KASSERT(curthread->t_curspl == 0); KASSERT(curthread->t_iplhigh_count == 0); callno = tf->tf_v0; /* * Initialize retval to 0. Many of the system calls don't * really return a value, just 0 for success and -1 on * error. Since retval is the value returned on success, * initialize it to 0 by default; thus it's not necessary to * deal with it except for calls that return other values, * like write. */ retval = 0; switch (callno) { case SYS_reboot: err = sys_reboot(tf->tf_a0); break; case SYS___time: err = sys___time((userptr_t)tf->tf_a0, (userptr_t)tf->tf_a1); break; /* Add stuff here */ case SYS__exit: _exit((int)tf->tf_a0); break; case SYS_chdir: err = chdir((const char*)tf->tf_a0); break; case SYS_close: err = close((int)tf->tf_a0, &retval); break; case SYS_dup2: err = dup2((int)tf->tf_a0, (int)tf->tf_a1, &retval); break; case SYS_execv: err = execv((const char*)tf->tf_a0, (char **)tf->tf_a1); break; case SYS_fork: err = fork(&retval); break; case SYS___getcwd: err = __getcwd((char*)tf->tf_a0, (size_t)tf->tf_a1, &retval); break; case SYS_getpid: err = getpid(&retval);//always return 0 break; case SYS_lseek: err = lseek((int)tf->tf_a0, (off_t)(tf->tf_a1 | tf->tf_a2), (int)tf->tf_a3, (off_t*)&retval); break; case SYS_open: err = open((const char*)tf->tf_a0, (int)tf->tf_a1, &retval); break; case SYS_read: err = read((int)tf->tf_a0, (void*)tf->tf_a1, (size_t)tf->tf_a2, &retval); break; case SYS_waitpid: err = waitpid((pid_t)tf->tf_a0, (int *)tf->tf_a1, (int)tf->tf_a2, &retval); break; case SYS_write: err = write((int)tf->tf_a0, (userptr_t)tf->tf_a1, (size_t)tf->tf_a2, &retval); break; default: kprintf("Unknown syscall %d\n", callno); err = ENOSYS; break; } if (err) { /* * Return the error code. This gets converted at * userlevel to a return value of -1 and the error * code in errno. */ tf->tf_v0 = err; tf->tf_a3 = 1; /* signal an error */ } else { /* Success. */ tf->tf_v0 = retval; tf->tf_a3 = 0; /* signal no error */ } /* * Now, advance the program counter, to avoid restarting * the syscall over and over again. */ tf->tf_epc += 4; /* Make sure the syscall code didn't forget to lower spl */ KASSERT(curthread->t_curspl == 0); /* ...or leak any spinlocks */ KASSERT(curthread->t_iplhigh_count == 0); curproc->rt = (curproc->rt == BACKGROUND_K ? BACKGROUND_U : INTERACTIVE_U); }
char *getcwd(char *buf, size_t size) { return (__getcwd(buf, size) < 0) ? NULL : buf; }
char * __realpath (const char *name, char *resolved) { char *rpath, *dest, *extra_buf = NULL; const char *start, *end, *rpath_limit; long int path_max; #ifdef S_ISLNK int num_links = 0; #endif if (name == NULL) { /* As per Single Unix Specification V2 we must return an error if either parameter is a null pointer. We extend this to allow the RESOLVED parameter to be NULL in case the we are expected to allocate the room for the return value. */ __set_errno (EINVAL); return NULL; } if (name[0] == '\0') { /* As per Single Unix Specification V2 we must return an error if the name argument points to an empty string. */ __set_errno (ENOENT); return NULL; } #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf (name, _PC_PATH_MAX); if (path_max <= 0) path_max = 1024; #endif if (resolved == NULL) { rpath = malloc (path_max); if (rpath == NULL) return NULL; } else rpath = resolved; rpath_limit = rpath + path_max; if (name[0] != '/') { if (!__getcwd (rpath, path_max)) { rpath[0] = '\0'; goto error; } dest = strchr (rpath, '\0'); } else { rpath[0] = '/'; dest = rpath + 1; } for (start = end = name; *start; start = end) { #ifdef _LIBC struct stat64 st; #else struct stat st; #endif /* Skip sequence of multiple path-separators. */ while (*start == '/') ++start; /* Find end of path component. */ for (end = start; *end && *end != '/'; ++end) /* Nothing. */; if (end - start == 0) break; else if (end - start == 1 && start[0] == '.') /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') { /* Back up to previous component, ignore if at root already. */ if (dest > rpath + 1) while ((--dest)[-1] != '/'); } else { size_t new_size; if (dest[-1] != '/') *dest++ = '/'; if (dest + (end - start) >= rpath_limit) { ptrdiff_t dest_offset = dest - rpath; char *new_rpath; if (resolved) { __set_errno (ENAMETOOLONG); if (dest > rpath + 1) dest--; *dest = '\0'; goto error; } new_size = rpath_limit - rpath; if (end - start + 1 > path_max) new_size += end - start + 1; else new_size += path_max; new_rpath = (char *) realloc (rpath, new_size); if (new_rpath == NULL) goto error; rpath = new_rpath; rpath_limit = rpath + new_size; dest = rpath + dest_offset; } #ifdef _LIBC dest = __mempcpy (dest, start, end - start); #else memcpy (dest, start, end - start); dest += end - start; #endif *dest = '\0'; #ifdef _LIBC if (__lxstat64 (_STAT_VER, rpath, &st) < 0) #else if (lstat (rpath, &st) < 0) #endif goto error; #ifdef S_ISLNK if (S_ISLNK (st.st_mode)) { char *buf; size_t len; int n; if (++num_links > MAXSYMLINKS) { __set_errno (ELOOP); goto error; } buf = allocsa (path_max); if (!buf) { errno = ENOMEM; goto error; } n = __readlink (rpath, buf, path_max); if (n < 0) { int saved_errno = errno; freesa (buf); errno = saved_errno; goto error; } buf[n] = '\0'; if (!extra_buf) { extra_buf = allocsa (path_max); if (!extra_buf) { freesa (buf); errno = ENOMEM; goto error; } } len = strlen (end); if ((long int) (n + len) >= path_max) { freesa (buf); __set_errno (ENAMETOOLONG); goto error; } /* Careful here, end may be a pointer into extra_buf... */ memmove (&extra_buf[n], end, len + 1); name = end = memcpy (extra_buf, buf, n); if (buf[0] == '/') dest = rpath + 1; /* It's an absolute symlink */ else /* Back up to previous component, ignore if at root already: */ if (dest > rpath + 1) while ((--dest)[-1] != '/'); } #endif } } if (dest > rpath + 1 && dest[-1] == '/') --dest; *dest = '\0'; if (extra_buf) freesa (extra_buf); return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath; error: { int saved_errno = errno; if (extra_buf) freesa (extra_buf); if (resolved) strcpy (resolved, rpath); else free (rpath); errno = saved_errno; } return NULL; }
char *csExpandName (const char *iName) { char outname [CS_MAXPATHLEN + 1]; int inp = 0, outp = 0, namelen = strlen (iName); while ((outp < CS_MAXPATHLEN) && (inp < namelen)) { char tmp [CS_MAXPATHLEN + 1]; int ptmp = 0; while ((inp < namelen) && (!IS_PATH_SEPARATOR(iName[inp]) )) tmp [ptmp++] = iName [inp++]; tmp [ptmp] = 0; if ((ptmp > 0) && (outp == 0) #if defined (CS_PLATFORM_DOS) || defined (CS_PLATFORM_WIN32) && ((inp >= namelen) || (iName [inp] != ':')) #endif ) { if (getcwd (outname, sizeof (outname)) == 0) { csPrintfErr ("csExpandName(): getcwd() error for %s (errno = %d)!\n", outname, errno); return 0; } outp = strlen (outname); if (strcmp (tmp, ".")) outname [outp++] = CS_PATH_SEPARATOR; } /* endif */ #if defined (CS_PLATFORM_DOS) || defined (CS_PLATFORM_WIN32) // If path starts with '/' (root), get current drive if ((ptmp == 0) && (outp == 0)) { getcwd (outname, sizeof (outname)); if (outname [1] == ':') outp = 2; } /* endif */ #endif if (strcmp (tmp, "..") == 0) { while ((outp > 0) && ((outname [outp - 1] == '/') || (outname [outp - 1] == CS_PATH_SEPARATOR) #if defined (CS_PLATFORM_DOS) || defined (CS_PLATFORM_WIN32) || (outname [outp - 1] == ':') #endif ) ) outp--; while ((outp > 0) && (outname [outp - 1] != '/') && (outname [outp - 1] != CS_PATH_SEPARATOR) #if defined (CS_PLATFORM_DOS) || defined (CS_PLATFORM_WIN32) && (outname [outp - 1] != ':') #endif ) outp--; } else if (strcmp (tmp, ".") == 0) { // do nothing } else if (strcmp (tmp, "~") == 0) { // strip all output path; start from scratch strcpy (outname, "~/"); outp = 2; } else { memcpy (&outname [outp], tmp, ptmp); outp += ptmp; if (inp < namelen) { #if defined (CS_PLATFORM_DOS) || defined (CS_PLATFORM_WIN32) if ((inp == 1) && (iName [inp] == ':')) if ((iName [inp + 1] == '/') || (iName [inp + 1] == CS_PATH_SEPARATOR)) outname [outp++] = ':'; else outp += __getcwd (iName [inp - 1], outname + outp - 1, sizeof (outname) - outp + 1) - 1; if ((outname [outp - 1] != '/') && (outname [outp - 1] != CS_PATH_SEPARATOR)) #endif outname [outp++] = CS_PATH_SEPARATOR; } } /* endif */ while ((inp < namelen) && ((iName [inp] == '/') || (iName [inp] == CS_PATH_SEPARATOR) #if defined (CS_PLATFORM_DOS) || defined (CS_PLATFORM_WIN32) || (iName [inp] == ':') #endif ) ) inp++; } /* endwhile */ char *ret = new char [outp + 1]; memcpy (ret, outname, outp); ret [outp] = 0; return ret; }
char * getcwd(char *buf, size_t size) { _gfs_hook_debug_v(fputs("Hooking getcwd\n", stderr)); return (__getcwd(buf, size)); }
static char * canonicalize (const char *name, char *resolved) { char *rpath, *dest, *extra_buf = NULL; const char *start, *end, *rpath_limit; long int path_max; int num_links = 0, old_errno; if (name == NULL) { /* As per Single Unix Specification V2 we must return an error if either parameter is a null pointer. We extend this to allow the RESOLVED parameter to be NULL in case the we are expected to allocate the room for the return value. */ __set_errno (EINVAL); return NULL; } if (name[0] == '\0') { /* As per Single Unix Specification V2 we must return an error if the name argument points to an empty string. */ __set_errno (ENOENT); return NULL; } #ifdef __WIN32__ { char *lpFilePart; int len; // fprintf(stderr, "name: %s\n", name); rpath = resolved ? __builtin_alloca (MAX_PATH) : malloc (MAX_PATH); // unix2winpath (name); // fprintf(stderr, "name: %s\n", name); len = GetFullPathName(name, MAX_PATH, rpath, &lpFilePart); /* GetFullPathName returns bogus paths for *nix-style paths, like * /foo/bar - it just prepends current drive to them. Keep them * intact (they need to be for relocation to work!). */ if (name[0] == '/') { strncpy (rpath, name, MAX_PATH - 1); rpath[MAX_PATH - 1] = '\0'; len = strlen (rpath); } // fprintf(stderr, "rpath: %s\n", rpath); if (len == 0) { //set_werrno; return NULL; } if (len > MAX_PATH) { if (resolved) __set_errno(ENAMETOOLONG); else { rpath = realloc(rpath, len + 2); GetFullPathName(name, len, rpath, &lpFilePart); // fprintf(stderr, "rpath: %s\n", rpath); } } // if ( ISDIRSEP(name[strlen(name)]) && !ISDIRSEP(rpath[len]) ) { // rpath[len] = '\\'; // rpath[len + 1] = 0; // } old_errno = errno; //if (!access (rpath, D_OK) && !ISDIRSEP(rpath[len - 1]) ){ if (!access (rpath, R_OK) && !ISDIRSEP(rpath[len - 1]) ){ rpath[len] = '\\'; rpath[len + 1] = 0; } errno = old_errno; win2unixpath (rpath); // fprintf(stderr, "rpath: %s\n", rpath); return resolved ? strcpy(resolved, rpath) : rpath ; } #else /* __WIN32__ */ #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf (name, _PC_PATH_MAX); if (path_max <= 0) path_max = 1024; #endif rpath = resolved ? __builtin_alloca (path_max) : malloc (path_max); rpath_limit = rpath + path_max; if (name[0] != '/') { if (!__getcwd (rpath, path_max)) { rpath[0] = '\0'; goto error; } dest = strchr (rpath, '\0'); } else { rpath[0] = '/'; dest = rpath + 1; } for (start = end = name; *start; start = end) { #ifdef _LIBC struct stat64 st; #else struct stat st; #endif int n; /* Skip sequence of multiple path-separators. */ while (*start == '/') ++start; /* Find end of path component. */ for (end = start; *end && *end != '/'; ++end) /* Nothing. */; if (end - start == 0) break; else if (end - start == 1 && start[0] == '.') /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') { /* Back up to previous component, ignore if at root already. */ if (dest > rpath + 1) while ((--dest)[-1] != '/'); } else { size_t new_size; if (dest[-1] != '/') *dest++ = '/'; if (dest + (end - start) >= rpath_limit) { ptrdiff_t dest_offset = dest - rpath; if (resolved) { __set_errno (ENAMETOOLONG); if (dest > rpath + 1) dest--; *dest = '\0'; goto error; } new_size = rpath_limit - rpath; if (end - start + 1 > path_max) new_size += end - start + 1; else new_size += path_max; rpath = realloc (rpath, new_size); rpath_limit = rpath + new_size; if (rpath == NULL) return NULL; dest = rpath + dest_offset; } #ifdef _LIBC dest = __mempcpy (dest, start, end - start); #else memcpy (dest, start, end - start); dest += end - start; #endif *dest = '\0'; #ifdef _LIBC if (__lxstat64 (_STAT_VER, rpath, &st) < 0) #else if (lstat (rpath, &st) < 0) #endif goto error; #if HAVE_READLINK if (S_ISLNK (st.st_mode)) { char *buf = __builtin_alloca (path_max); size_t len; if (++num_links > MAXSYMLINKS) { __set_errno (ELOOP); goto error; } n = __readlink (rpath, buf, path_max); if (n < 0) goto error; buf[n] = '\0'; if (!extra_buf) extra_buf = __builtin_alloca (path_max); len = strlen (end); if ((long int) (n + len) >= path_max) { __set_errno (ENAMETOOLONG); goto error; } /* Careful here, end may be a pointer into extra_buf... */ memmove (&extra_buf[n], end, len + 1); name = end = memcpy (extra_buf, buf, n); if (buf[0] == '/') dest = rpath + 1; /* It's an absolute symlink */ else /* Back up to previous component, ignore if at root already: */ if (dest > rpath + 1) while ((--dest)[-1] != '/'); } #endif } } if (dest > rpath + 1 && dest[-1] == '/') --dest; *dest = '\0'; return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath; error: if (resolved) strcpy (resolved, rpath); else free (rpath); return NULL; #endif /* __WIN32__ */ }
char * getcwd(char *pt, size_t size) { struct dirent *dp; DIR *dir = NULL; dev_t dev; ino_t ino; int first; char *bpt; struct stat s; dev_t root_dev; ino_t root_ino; size_t ptsize; int save_errno; char *ept, c; int fd; /* * If no buffer specified by the user, allocate one as necessary. * If a buffer is specified, the size has to be non-zero. The path * is built from the end of the buffer backwards. */ if (pt) { ptsize = 0; if (!size) { errno = EINVAL; return (NULL); } if (size == 1) { errno = ERANGE; return (NULL); } ept = pt + size; } else { if ((pt = malloc(ptsize = PATH_MAX)) == NULL) return (NULL); ept = pt + ptsize; } if (__getcwd(pt, ept - pt) == 0) { if (*pt != '/') { bpt = pt; ept = pt + strlen(pt) - 1; while (bpt < ept) { c = *bpt; *bpt++ = *ept; *ept-- = c; } } return (pt); } bpt = ept - 1; *bpt = '\0'; /* Save root values, so know when to stop. */ if (stat("/", &s)) goto err; root_dev = s.st_dev; root_ino = s.st_ino; errno = 0; /* XXX readdir has no error return. */ for (first = 1;; first = 0) { /* Stat the current level. */ if (dir != NULL ? _fstat(_dirfd(dir), &s) : lstat(".", &s)) goto err; /* Save current node values. */ ino = s.st_ino; dev = s.st_dev; /* Check for reaching root. */ if (root_dev == dev && root_ino == ino) { *--bpt = '/'; /* * It's unclear that it's a requirement to copy the * path to the beginning of the buffer, but it's always * been that way and stuff would probably break. */ bcopy(bpt, pt, ept - bpt); if (dir) (void) closedir(dir); return (pt); } /* Open and stat parent directory. */ fd = _openat(dir != NULL ? _dirfd(dir) : AT_FDCWD, "..", O_RDONLY | O_CLOEXEC); if (fd == -1) goto err; if (dir) (void) closedir(dir); if (!(dir = fdopendir(fd)) || _fstat(_dirfd(dir), &s)) { _close(fd); goto err; } /* * If it's a mount point, have to stat each element because * the inode number in the directory is for the entry in the * parent directory, not the inode number of the mounted file. */ save_errno = 0; if (s.st_dev == dev) { for (;;) { if (!(dp = readdir(dir))) goto notfound; if (dp->d_fileno == ino) break; } } else for (;;) { if (!(dp = readdir(dir))) goto notfound; if (ISDOT(dp)) continue; /* Save the first error for later. */ if (fstatat(_dirfd(dir), dp->d_name, &s, AT_SYMLINK_NOFOLLOW)) { if (!save_errno) save_errno = errno; errno = 0; continue; } if (s.st_dev == dev && s.st_ino == ino) break; } /* * Check for length of the current name, preceding slash, * leading slash. */ while (bpt - pt < dp->d_namlen + (first ? 1 : 2)) { size_t len, off; if (!ptsize) { errno = ERANGE; goto err; } off = bpt - pt; len = ept - bpt; if ((pt = reallocf(pt, ptsize *= 2)) == NULL) goto err; bpt = pt + off; ept = pt + ptsize; bcopy(bpt, ept - len, len); bpt = ept - len; } if (!first) *--bpt = '/'; bpt -= dp->d_namlen; bcopy(dp->d_name, bpt, dp->d_namlen); } notfound: /* * If readdir set errno, use it, not any saved error; otherwise, * didn't find the current directory in its parent directory, set * errno to ENOENT. */ if (!errno) errno = save_errno ? save_errno : ENOENT; /* FALLTHROUGH */ err: save_errno = errno; if (ptsize) free(pt); if (dir) (void) closedir(dir); errno = save_errno; return (NULL); }
/* Determine the directories we are looking for data in. */ void internal_function __gconv_get_path (void) { struct path_elem *result; __libc_lock_define_initialized (static, lock); __libc_lock_lock (lock); /* Make sure there wasn't a second thread doing it already. */ result = (struct path_elem *) __gconv_path_elem; if (result == NULL) { /* Determine the complete path first. */ char *gconv_path; size_t gconv_path_len; char *elem; char *oldp; char *cp; int nelems; char *cwd; size_t cwdlen; if (__gconv_path_envvar == NULL) { /* No user-defined path. Make a modifiable copy of the default path. */ gconv_path = strdupa (default_gconv_path); gconv_path_len = sizeof (default_gconv_path); cwd = NULL; cwdlen = 0; } else { /* Append the default path to the user-defined path. */ size_t user_len = strlen (__gconv_path_envvar); gconv_path_len = user_len + 1 + sizeof (default_gconv_path); gconv_path = alloca (gconv_path_len); __mempcpy (__mempcpy (__mempcpy (gconv_path, __gconv_path_envvar, user_len), ":", 1), default_gconv_path, sizeof (default_gconv_path)); cwd = __getcwd (NULL, 0); cwdlen = strlen (cwd); } assert (default_gconv_path[0] == '/'); /* In a first pass we calculate the number of elements. */ oldp = NULL; cp = strchr (gconv_path, ':'); nelems = 1; while (cp != NULL) { if (cp != oldp + 1) ++nelems; oldp = cp; cp = strchr (cp + 1, ':'); } /* Allocate the memory for the result. */ result = (struct path_elem *) malloc ((nelems + 1) * sizeof (struct path_elem) + gconv_path_len + nelems + (nelems - 1) * (cwdlen + 1)); if (result != NULL) { char *strspace = (char *) &result[nelems + 1]; int n = 0; /* Separate the individual parts. */ __gconv_max_path_elem_len = 0; elem = __strtok_r (gconv_path, ":", &gconv_path); assert (elem != NULL); do { result[n].name = strspace; if (elem[0] != '/') { assert (cwd != NULL); strspace = __mempcpy (strspace, cwd, cwdlen); *strspace++ = '/'; } strspace = __stpcpy (strspace, elem); if (strspace[-1] != '/') *strspace++ = '/'; result[n].len = strspace - result[n].name; if (result[n].len > __gconv_max_path_elem_len) __gconv_max_path_elem_len = result[n].len; *strspace++ = '\0'; ++n; } while ((elem = __strtok_r (NULL, ":", &gconv_path)) != NULL); result[n].name = NULL; result[n].len = 0; } __gconv_path_elem = result ?: (struct path_elem *) &empty_path_elem; if (cwd != NULL) free (cwd); }