2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
25 * $XConsortium: util_file.c /main/4 1995/11/06 18:54:05 rswiston $
27 * @(#)util_file.c 1.24 19 Apr 1995 cde_app_builder/src/libAButil
29 * RESTRICTED CONFIDENTIAL INFORMATION:
31 * The information in this document is subject to special
32 * restrictions in a confidential disclosure agreement between
33 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
34 * document outside HP, IBM, Sun, USL, SCO, or Univel without
35 * Sun's specific written approval. This document and all copies
36 * and derivative works thereof must be returned or destroyed at
39 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
50 #include <sys/param.h>
51 #include <sys/types.h>
54 #include <ab_private/abio.h>
57 /*************************************************************************
59 ** Private Function Declarations **
61 **************************************************************************/
63 /*************************************************************************
67 **************************************************************************/
68 #define AB_EXT_LENGTH 3
70 /*************************************************************************
72 ** Function Definitions **
74 **************************************************************************/
77 * removes all buffering from a file. This is useful for debugging
78 * to avoid losing data, and to keep stdout and stderr messages from
79 * getting jumbled (ordered is basically guaranteed if both streams
82 * This *is* a performance hit, so don't use this except when debugging.
83 * Note that stderr is always unbuffered.
86 util_unbuffer_file(FILE *fp)
89 int iRC= 0; /* return code */
93 /* this is too much - actually waits for sync to disk, and runs
97 if ((iRC= fileMode= fcntl(fileno(fp), F_GETFL)) >= 0)
100 iRC= fcntl(fileno(fp), F_SETFL, fileMode);
110 util_file_exists(STRING fileName)
112 struct stat fileInfo;
113 return (stat(fileName, &fileInfo) == 0);
117 /* Returns the file size, or ERR_ value (<0) on error
121 util_file_size(STRING fileName)
123 struct stat fileInfo;
124 if (stat(fileName, &fileInfo) != 0)
126 return ERR_FILE_NOT_FOUND;
128 return (long)fileInfo.st_size;
133 * Extension should not contain it's leading "."
135 * if extension is NULL or the empty string, returns TRUE if the name
139 util_file_name_has_extension(STRING fileName, STRING extension)
141 BOOL hasExtension= FALSE;
143 if (extension == NULL)
145 hasExtension = ( (fileName == NULL) || (strlen(fileName) == 0) );
149 if (fileName == NULL)
155 char *dotPtr= strrchr(fileName, '.');
162 hasExtension= util_streq(dotPtr+1, extension);
172 util_file_name_has_ab_extension(STRING fileName)
174 BOOL hasExtension= FALSE;
175 char *dotPtr= strrchr(fileName, '.');
179 hasExtension= (strncmp(dotPtr, ".bi", 3) == 0);
186 util_get_file_name_from_path(
192 char *slashPtr= strrchr(path, '/');
193 if (slashPtr == NULL)
195 strncpy(fileNameBuf, path, fileNameBufSize);
199 strncpy(fileNameBuf, slashPtr+1, fileNameBufSize);
201 fileNameBuf[fileNameBufSize-1]= 0;
207 * If path is not absolute, directory is "."
209 * The directory name returned does NOT have a trailing '/'. (The
210 * only exception being the directory "/" .
213 util_get_dir_name_from_path(
219 char *slashPtr= strrchr(path, '/');
220 assert(dirNameBufSize > 1);
221 if (slashPtr == NULL)
223 /* no directory name */
224 strcpy(dirNameBuf, ".");
226 else if (slashPtr == path)
229 strcpy(dirNameBuf, "/");
233 /* directory and file name */
235 util_min(dirNameBufSize, (((int)(slashPtr - path))+1));
236 strncpy(dirNameBuf, path, copyCount);
237 dirNameBuf[dirNameBufSize-1]= 0;
238 while ((copyCount > 1) && (dirNameBuf[copyCount-1] == '/'))
242 dirNameBuf[copyCount]= 0;
250 * Truncates the open file to length bytes.
252 * ftruncate() is not defined in POSIX, so the header files don't define
253 * it when _POSIX_SOURCE is not defined. We're going to use it, anyway,
254 * and this prototype is identical in the header files for all the
255 * platforms (Sun/HP/IBM).
260 extern ftruncate(int filedes, off_t length);
265 util_fdtruncate(int filedes, off_t length)
267 return ftruncate(filedes, length);
272 util_directory_exists(STRING dir_name)
275 struct stat dir_info;
277 if (stat(dir_name, &dir_info) != 0)
281 if (S_ISDIR(dir_info.st_mode))
292 util_paths_are_same_file(STRING path1, STRING path2)
294 BOOL same_file = FALSE;
295 struct stat file_info1;
296 struct stat file_info2;
298 if (stat(path1, &file_info1) != 0)
302 if (stat(path2, &file_info2) != 0)
307 same_file = ( (file_info1.st_dev == file_info2.st_dev)
308 && (file_info1.st_ino == file_info2.st_ino) );
316 * Converts the path to a relative path from from_dir.
318 * for path and from_dir, NULL, "", or "." = current directory
320 * Returns "." if path and from_dir reference the same directory
323 util_cvt_path_to_relative(
330 #define path_is_dot(arg_path) \
331 (util_strempty(arg_path) || util_streq(arg_path, "."))
333 int return_value = 0;
334 BOOL found_relative= FALSE;
336 BOOL more_path = TRUE;
337 char cwd[MAXPATHLEN]= "";
339 char *rightmost_slash= NULL;
340 char *last_rightmost_slash= NULL;
342 if ( (path_is_dot(from_dir) && path_is_dot(path_in))
343 || (util_streq(from_dir, path_in))
346 /* the strings are equivalent! */
352 * Determine "from" dir.
354 if (path_is_dot(from_dir))
364 * Determine the directory we are trying to convert.
366 if (path_is_dot(path_in))
368 if (getcwd(cwd, MAXPATHLEN) == NULL)
380 if (!util_directory_exists(from))
386 rightmost_slash = NULL;
387 last_rightmost_slash = NULL;
389 while ((!found_relative) && more_path)
391 if (util_paths_are_same_file(from, path))
393 found_relative = TRUE;
398 * Get the name of the next dir up
400 rightmost_slash= strrchr(path, '/');
401 if (last_rightmost_slash != NULL)
403 *last_rightmost_slash = '/';
405 last_rightmost_slash= rightmost_slash;
408 * Put in a NULL, so that util_paths_are_same_file is happy
410 if (rightmost_slash == NULL)
416 (*rightmost_slash) = 0;
420 if (rightmost_slash != NULL)
422 *rightmost_slash = '/';
427 if (rightmost_slash == NULL)
429 /* they are the same damn file (directory)! */
430 strncpy(buf, ".", buf_size);
435 while ((*rightmost_slash == '/') && (*rightmost_slash != 0))
439 strncpy(buf, rightmost_slash, buf_size);
445 strncpy(buf, path, buf_size);
454 /* This routine will create a directory hierarchy in the
455 * current working directory if the hierarchy does not
456 * already exist. If mkdir fails, errno will be set and
457 * a negative value will be returned.
464 STRING slash_ptr = NULL;
467 /* As an example: path -> "x/y/z", so slash_ptr points
468 * to the same string.
471 while (slash_ptr != NULL)
473 /* 1) x/y/z 2) x/y/z 3) x/y/z
476 * slash_ptr slash_ptr slash_ptr == NULL
478 slash_ptr = strchr(slash_ptr, '/');
480 /* 1) x NULL y/z 2) x/y NULL z
483 * slash_ptr slash_ptr
485 if (slash_ptr != NULL)
490 /* Make the directory named:
491 * 1) "x" 2) "x/y" 3) "x/y/z"
494 ret = mkdir(path, 0777);
496 /* If there was an error return -1 */
497 if ( ret != 0 && errno != EEXIST )
502 if ( slash_ptr != NULL )
504 /* 1) x/y/z 2) x/y/z 3) slash_ptr == NULL
507 * slash_ptr slash_ptr
511 /* If there are multiple slashes, skip them.
515 * slash_ptr slash_ptr
517 while (*slash_ptr == '/')
527 util_path_is_absolute(
539 /* This routine is passed in an absolute path name (from the file
540 * chooser) and derives the module or project name for the ABObj
541 * struct. The obj name is passed back in the objname parameter.
542 * This routine assumes that objname already has allocated space.
545 util_derive_name_from_path(
550 char *filename, *name;
553 if ( util_file_name_has_ab_extension(fullpath) )
556 * Check return value of strrchr before adding 1 to it
558 if (filename = strrchr(fullpath, '/'))
559 name = (STRING)strdup(filename + 1);
561 name = (STRING)strdup(fullpath);
563 len = strlen(name) - (AB_EXT_LENGTH + 1);
564 strncpy(objname, name, len);
571 * Check return value of strrchr before adding 1 to it
573 if (filename = strrchr(fullpath, '/'))
574 strcpy(objname, filename + 1);
576 strcpy(objname, fullpath);
581 /* This routine is passed in a name (from the project or module
582 * name dialog). It checks the name for the ".bil" or ".bip"
583 * extension and strips it off if the name has it. The project
584 * or module name is passed back in the new_name parameter. This
585 * routine assumes that new_name already has allocated space.
595 if ( util_file_name_has_ab_extension(name) )
597 len = strlen(name) - (AB_EXT_LENGTH + 1);
598 strncpy(new_name, name, len);
599 new_name[len] = '\0';
603 strcpy(new_name, name);
610 util_file_is_regular_file(STRING filename)
612 BOOL IsRegFile = FALSE;
613 struct stat file_info;
615 if (stat(filename, &file_info) != 0)
619 if (S_ISREG(file_info.st_mode))
629 util_file_is_directory(STRING filename)
632 struct stat file_info;
634 if (stat(filename, &file_info) != 0)
638 if (S_ISDIR(file_info.st_mode))
649 * from fopen() man page: legal types are:
651 * r, rb, w, wb, a, ab,
652 * r+, r+b, rb+, w+, w+b, wb+, a+, a+b, ab+
654 * The 'b' option is ignored.
658 util_fopen_locked(const char *filename, const char *accessType)
661 char char1 = accessType[0];
663 ( (accessType[1] != 0)
664 && ((accessType[1] == '+') || (accessType[2] == '+')));
665 BOOL truncateFile = FALSE;
670 * If a truncated open, open the existing file, first. That way, we
671 * can get a write lock before actually doing the truncate.
673 switch (accessType[0])
676 file = fopen(filename, accessType);
689 file = fopen(filename, "r+"); /* use existing, first! */
690 if ((file == NULL) && (errno == ENOENT))
692 file = fopen(filename, accessType);
699 file = fopen(filename, accessType);
704 errno = 0; /* file is NULL */
709 * Get the appropriate lock on the file.
710 * Truncate the file, if necessary.
712 if ((file != NULL) && (lockType != -1))
714 if ( (util_flock(file, TRUE, lockType, 0, 0) >= 0)
717 util_ftruncate(file, 0, accessType);
726 util_flock(FILE *file, BOOL wait, int lockType, off_t offset, off_t length)
729 int fcntlParam = (wait? F_SETLKW:F_SETLK);
731 lock.l_type = lockType;
732 lock.l_whence = SEEK_SET;
733 lock.l_start = offset;
735 lock.l_pid = (pid_t)-1;
738 if (debugging() && wait)
740 if (fcntl(fileno(file), F_SETLK, (void*)&lock) == 0)
747 /* didn't get the lock - we're going to block */
748 util_dprintf(1, "Waiting for lock [%s]...\n",
749 (fcntlParam == F_RDLCK? "READ":
750 (fcntlParam == F_WRLCK? "WRITE":
757 if (fcntl(fileno(file), fcntlParam, (void*)&lock) != 0)
767 util_funlock(FILE *file, off_t offset, off_t length)
771 lock.l_type = F_UNLCK;
772 lock.l_whence = SEEK_SET;
773 lock.l_start = offset;
775 lock.l_pid = (pid_t)-1;
777 if (fcntl(fileno(file), F_SETLKW, (void*)&lock) != 0)
787 util_ftruncate(FILE *file, off_t length, const char *accessType)
789 int fd = fileno(file);
790 off_t offset = ftell(file);
792 util_fdtruncate(fd, length);
795 * Associate the stream with the file descriptor fildes.
797 fdopen(fd, accessType);
800 * Perform a seek on the stream, just to make sure it's in sync.
804 fseek(file, 0, SEEK_END);
808 fseek(file, offset, SEEK_SET);