X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Ffile-name.c;h=86c8e17e467d45c3cf7edac34166b20357cba62f;hb=685407ad62911e5edb1ec093a01ec9e46563af44;hp=23d7ee0889f2c75460e8d479eb177b7acc2f75d9;hpb=458d169f64134f4e0a9d9b72398666a01761fcf8;p=pspp-builds.git diff --git a/src/data/file-name.c b/src/data/file-name.c index 23d7ee08..86c8e17e 100644 --- a/src/data/file-name.c +++ b/src/data/file-name.c @@ -20,20 +20,25 @@ #include #include +#include #include #include +#include #include "intprops.h" #include "minmax.h" #include "dirname.h" +#include "xmalloca.h" -#include -#include #include +#include +#include #include #include #include +#include "xalloc.h" + #include "gettext.h" #define _(msgid) gettext (msgid) @@ -252,7 +257,7 @@ safety_violation (const char *fn) FILE * fn_open (const char *fn, const char *mode) { - assert (mode[0] == 'r' || mode[0] == 'w'); + assert (mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a'); if (mode[0] == 'r' && (!strcmp (fn, "stdin") || !strcmp (fn, "-"))) return stdin; @@ -264,26 +269,26 @@ fn_open (const char *fn, const char *mode) #if HAVE_POPEN if (fn[0] == '|') { - if (get_safer_mode ()) + if (settings_get_safer_mode ()) return safety_violation (fn); - return popen (&fn[1], mode); + return popen (&fn[1], mode[0] == 'r' ? "r" : "w"); } else if (*fn && fn[strlen (fn) - 1] == '|') { char *s; FILE *f; - if (get_safer_mode ()) + if (settings_get_safer_mode ()) return safety_violation (fn); - s = local_alloc (strlen (fn)); + s = xmalloca (strlen (fn)); memcpy (s, fn, strlen (fn) - 1); s[strlen (fn) - 1] = 0; - f = popen (s, mode); + f = popen (s, mode[0] == 'r' ? "r" : "w"); - local_free (s); + freea (s); return f; } @@ -320,60 +325,48 @@ fn_close (const char *fn, FILE *f) return fclose (f); } -#if !(defined _WIN32 || defined __WIN32__) -/* A file's identity. */ -struct file_identity +/* Creates a new file named FN with the given PERMISSIONS bits, + and returns a stream for it or a null pointer on failure. + MODE should be "w" or "wb". */ +FILE * +create_stream (const char *fn, const char *mode, mode_t permissions) { - dev_t device; /* Device number. */ - ino_t inode; /* Inode number. */ -}; + int fd; + FILE *stream; -/* Returns a pointer to a dynamically allocated structure whose - value can be used to tell whether two files are actually the - same file. Returns a null pointer if no information about the - file is available, perhaps because it does not exist. The - caller is responsible for freeing the structure with - fn_free_identity() when finished. */ -struct file_identity * -fn_get_identity (const char *file_name) -{ - struct stat s; + fd = open (fn, O_WRONLY | O_CREAT | O_TRUNC, permissions); + if (fd < 0) + return NULL; - if (stat (file_name, &s) == 0) + stream = fdopen (fd, mode); + if (stream == NULL) { - struct file_identity *identity = xmalloc (sizeof *identity); - identity->device = s.st_dev; - identity->inode = s.st_ino; - return identity; + int save_errno = errno; + close (fd); + errno = save_errno; } - else - return NULL; -} -/* Frees IDENTITY obtained from fn_get_identity(). */ -void -fn_free_identity (struct file_identity *identity) -{ - free (identity); + return stream; } -/* Compares A and B, returning a strcmp()-type result. */ -int -fn_compare_file_identities (const struct file_identity *a, - const struct file_identity *b) -{ - assert (a != NULL); - assert (b != NULL); - if (a->device != b->device) - return a->device < b->device ? -1 : 1; - else - return a->inode < b->inode ? -1 : a->inode > b->inode; -} -#else /* Windows */ -/* A file's identity. */ +/* A file's identity: + + - For a file that exists, this is its device and inode. + + - For a file that does not exist, but which has a directory + name that exists, this is the device and inode of the + directory, plus the file's base name. + + - For a file that does not exist and has a nonexistent + directory, this is the file name. + + Windows doesn't have inode numbers, so we just use the name + there. */ struct file_identity { - char *normalized_file_name; /* File's normalized name. */ + dev_t device; /* Device number. */ + ino_t inode; /* Inode number. */ + char *name; /* File name, where needed, otherwise NULL. */ }; /* Returns a pointer to a dynamically allocated structure whose @@ -386,12 +379,40 @@ struct file_identity * fn_get_identity (const char *file_name) { struct file_identity *identity = xmalloc (sizeof *identity); - char cname[PATH_MAX]; - if (GetFullPathName (file_name, sizeof cname, cname, NULL)) - identity->normalized_file_name = xstrdup (cname); +#if !(defined _WIN32 || defined __WIN32__) + struct stat s; + if (lstat (file_name, &s) == 0) + { + identity->device = s.st_dev; + identity->inode = s.st_ino; + identity->name = NULL; + } else - identity->normalized_file_name = xstrdup (file_name); + { + char *dir = dir_name (file_name); + if (last_component (file_name) != NULL && stat (dir, &s) == 0) + { + identity->device = s.st_dev; + identity->inode = s.st_ino; + identity->name = base_name (file_name); + } + else + { + identity->device = 0; + identity->inode = 0; + identity->name = xstrdup (file_name); + } + free (dir); + } +#else /* Windows */ + char cname[PATH_MAX]; + int ok = GetFullPathName (file_name, sizeof cname, cname, NULL); + identity->device = 0; + identity->inode = 0; + identity->name = xstrdup (ok ? cname : file_name); + str_lowercase (identity->name); +#endif /* Windows */ return identity; } @@ -402,7 +423,7 @@ fn_free_identity (struct file_identity *identity) { if (identity != NULL) { - free (identity->normalized_file_name); + free (identity->name); free (identity); } } @@ -412,6 +433,22 @@ int fn_compare_file_identities (const struct file_identity *a, const struct file_identity *b) { - return strcasecmp (a->normalized_file_name, b->normalized_file_name); + if (a->device != b->device) + return a->device < b->device ? -1 : 1; + else if (a->inode != b->inode) + return a->inode < b->inode ? -1 : 1; + else if (a->name != NULL) + return b->name != NULL ? strcmp (a->name, b->name) : 1; + else + return b->name != NULL ? -1 : 0; +} + +/* Returns a hash value for IDENTITY. */ +unsigned int +fn_hash_identity (const struct file_identity *identity) +{ + unsigned int hash = identity->device ^ identity->inode; + if (identity->name != NULL) + hash ^= hsh_hash_string (identity->name); + return hash; } -#endif /* Windows */