char * gfs_utimes(const char *gfarm_url, const struct gfarm_timespec *tsp) { char *e, *gfarm_file; struct gfarm_path_info pi; struct timeval now; e = gfarm_url_make_path(gfarm_url, &gfarm_file); if (e != NULL) return (e); e = gfarm_path_info_get(gfarm_file, &pi); free(gfarm_file); if (e != NULL) return (e); e = gfarm_path_info_access(&pi, GFS_W_OK); if (e != NULL) return (e); gettimeofday(&now, NULL); if (tsp == NULL) { pi.status.st_atimespec.tv_sec = pi.status.st_mtimespec.tv_sec = now.tv_sec; pi.status.st_atimespec.tv_nsec = pi.status.st_mtimespec.tv_nsec = now.tv_usec * 1000; } else { pi.status.st_atimespec = tsp[0]; pi.status.st_mtimespec = tsp[1]; } pi.status.st_ctimespec.tv_sec = now.tv_sec; pi.status.st_ctimespec.tv_nsec = now.tv_usec * 1000; e = gfarm_path_info_replace(pi.pathname, &pi); gfarm_path_info_free(&pi); return (e); }
char * gfs_pio_open(const char *url, int flags, GFS_File *gfp) { char *e, *pathname; GFS_File gf; gfarm_timerval_t t1, t2; gfs_profile(gfarm_gettimerval(&t1)); if ((flags & GFARM_FILE_ACCMODE) != GFARM_FILE_RDONLY) { #if 0 /* XXX - ROOT I/O opens a new file with O_CREAT|O_RDRW mode. */ e = GFARM_ERR_OPERATION_NOT_SUPPORTED; /* XXX */ goto finish; #else flags |= GFARM_FILE_CREATE; #endif } e = gfarm_url_make_path(url, &pathname); if (e != NULL) goto finish; e = gfs_file_alloc(&gf); if (e != NULL) { free(pathname); goto finish; } gf->open_flags = flags; gf->mode |= GFS_FILE_MODE_READ; if (((flags & GFARM_FILE_ACCMODE) == GFARM_FILE_RDWR) || ((flags & GFARM_FILE_ACCMODE) == GFARM_FILE_WRONLY)) gf->mode |= GFS_FILE_MODE_WRITE; e = gfarm_path_info_get(pathname, &gf->pi); free(pathname); if (e != NULL) goto finish; e = gfarm_path_info_access(&gf->pi, GFS_R_OK); if (e != NULL) { gfarm_path_info_free(&gf->pi); gfs_file_free(gf); goto finish; } if (!GFARM_S_ISREG(gf->pi.status.st_mode)) { if (GFARM_S_ISDIR(gf->pi.status.st_mode)) e = GFARM_ERR_IS_A_DIRECTORY; else e = GFARM_ERR_OPERATION_NOT_SUPPORTED; gfarm_path_info_free(&gf->pi); gfs_file_free(gf); goto finish; } gf->mode |= GFS_FILE_MODE_NSEGMENTS_FIXED; *gfp = gf; e = NULL; finish: gfs_profile(gfarm_gettimerval(&t2)); gfs_profile(gfs_pio_open_time += gfarm_timerval_sub(&t2, &t1)); return (e); }
char * gfarm_url_section_replicate_from_to(char *gfarm_url, char *section, char *srchost, char *dsthost) { char *e, *gfarm_file, *canonical_hostname, *if_hostname; struct sockaddr peer_addr; struct gfarm_path_info pi; struct gfarm_file_section_info si; gfarm_mode_t mode_allowed = 0; e = gfarm_url_make_path(gfarm_url, &gfarm_file); if (e != NULL) goto finish; e = gfarm_path_info_get(gfarm_file, &pi); if (e != NULL) goto finish_gfarm_file; e = gfarm_file_section_info_get(gfarm_file, section, &si); if (e != NULL) goto finish_path_info; e = gfarm_host_get_canonical_name(srchost, &canonical_hostname); if (e != NULL) goto finish_canonical_hostname; /* reflect "address_use" directive in the `srchost' */ e = gfarm_host_address_get(srchost, gfarm_spool_server_port, &peer_addr, &if_hostname); if (e != NULL) goto finish_section_info; /* * XXX - if the owner of a file is not the same, permit a * group/other write access - This should be fixed in the next * major release. */ if (strcmp(pi.status.st_user, gfarm_get_global_username()) != 0) { e = gfarm_path_info_access(&pi, GFS_R_OK); if (e != NULL) goto finish_path_info; mode_allowed = 022; } e = gfarm_file_section_replicate_from_to_internal( gfarm_file, section, (pi.status.st_mode | mode_allowed) & GFARM_S_ALLPERM, si.filesize, canonical_hostname, if_hostname, dsthost); free(if_hostname); finish_canonical_hostname: free(canonical_hostname); finish_section_info: gfarm_file_section_info_free(&si); finish_path_info: gfarm_path_info_free(&pi); finish_gfarm_file: free(gfarm_file); finish: return (e); }
char * gfs_access(const char *gfarm_url, int mode) { char *e, *gfarm_file; struct gfarm_path_info pi; gfarm_mode_t stat_mode; int stat_nsections, nsections; struct gfarm_file_section_info *sections; e = gfarm_url_make_path(gfarm_url, &gfarm_file); if (e != NULL) return (e); e = gfarm_path_info_get(gfarm_file, &pi); if (e != NULL) { free(gfarm_file); return (e); } stat_mode = pi.status.st_mode; stat_nsections = pi.status.st_nsections; e = gfarm_path_info_access(&pi, mode); gfarm_path_info_free(&pi); if (e != NULL) { free(gfarm_file); return (e); } if (GFARM_S_ISDIR(stat_mode)) { free(gfarm_file); return (NULL); } /* * Check all fragments are ready or not. * XXX - is this check necessary? */ e = gfarm_file_section_info_get_all_by_file( gfarm_file, &nsections, §ions); free(gfarm_file); if (e != NULL) return (e); gfarm_file_section_info_free_all(nsections, sections); if (!GFARM_S_IS_PROGRAM(stat_mode) && nsections != stat_nsections) e = GFARM_ERR_FRAGMENT_NUMBER_DOES_NOT_MATCH; return (e); }
char * gfarm_url_section_replicate_to(char *gfarm_url, char *section, char *dsthost) { char *e, *gfarm_file; struct gfarm_path_info pi; struct gfarm_file_section_info si; gfarm_mode_t mode_allowed = 0; e = gfarm_url_make_path(gfarm_url, &gfarm_file); if (e != NULL) goto finish; e = gfarm_path_info_get(gfarm_file, &pi); if (e != NULL) goto finish_gfarm_file; e = gfarm_file_section_info_get(gfarm_file, section, &si); if (e != NULL) goto finish_path_info; /* * XXX - if the owner of a file is not the same, permit a * group/other write access - This should be fixed in the next * major release. */ if (strcmp(pi.status.st_user, gfarm_get_global_username()) != 0) { e = gfarm_path_info_access(&pi, GFS_R_OK); if (e != NULL) goto finish_path_info; mode_allowed = 022; } e = gfarm_file_section_replicate_to_internal( gfarm_file, section, (pi.status.st_mode | mode_allowed) & GFARM_S_ALLPERM, si.filesize, dsthost); gfarm_file_section_info_free(&si); finish_path_info: gfarm_path_info_free(&pi); finish_gfarm_file: free(gfarm_file); finish: return (e); }
static char * gfs_pio_open_check_perm(GFS_File gf) { char *e; int check= 0; if ((gf->mode & GFS_FILE_MODE_READ) != 0) check |= GFS_R_OK; if ((gf->mode & GFS_FILE_MODE_WRITE) != 0 || (gf->open_flags & GFARM_FILE_TRUNC) != 0) check |= GFS_W_OK; e = gfarm_path_info_access(&gf->pi, check); if (e != NULL) return (e); if (!GFARM_S_ISREG(gf->pi.status.st_mode)) { if (GFARM_S_ISDIR(gf->pi.status.st_mode)) return (GFARM_ERR_IS_A_DIRECTORY); else return (GFARM_ERR_OPERATION_NOT_SUPPORTED); } return (NULL); }
char * gfs_access(char *gfarm_url, int mode) { char *e, *gfarm_file; struct gfarm_path_info pi; int nsections; struct gfarm_file_section_info *sections; e = gfarm_url_make_path(gfarm_url, &gfarm_file); if (e != NULL) return (e); e = gfarm_path_info_get(gfarm_file, &pi); if (e != NULL) { free(gfarm_file); return (e); } /* * Check whether the gfarm_url can be accessible by other * processes or not. * * XXX - temporal solution until file locking will be implemented. */ e = gfarm_file_section_info_get_all_by_file(gfarm_file, &nsections, §ions); free(gfarm_file); if (e != NULL) { return (e); } gfarm_file_section_info_free_all(nsections, sections); if (!GFARM_S_IS_PROGRAM(pi.status.st_mode) && nsections != pi.status.st_nsections) return (GFARM_ERR_FRAGMENT_NUMBER_DOES_NOT_MATCH); e = gfarm_path_info_access(&pi, mode); gfarm_path_info_free(&pi); return (e); }
char * gfarm_canonical_path_for_creation(const char *gfarm_file, char **canonic_pathp) { const char *basename, *p0; char *e, *p1, *dir, *dir_canonic, *lastc, cwd[PATH_MAX + 1]; *canonic_pathp = NULL; /* cause SEGV, if return value is ignored */ /* '' or 'gfarm:' case */ if (gfarm_file[0] == '\0') { e = gfs_getcwd(cwd, sizeof(cwd)); if (e != NULL) return (e); p0 = cwd; } else p0 = gfarm_file; /* Expand '~'. */ e = gfarm_path_expand_home(p0, &p1); if (e != NULL) return (e); /* Eliminate unnecessary '/'s following the basename. */ lastc = &p1[strlen(p1) - 1]; if (*lastc == '/') { while (p1 < lastc && *lastc == '/') --lastc; if (p1 == lastc) { /* * In this case, given gfarm_file is '/' or contains * only several '/'s. This means to attempt to create * the root directory. Because the root directory * should exist, the attempt will fail with the error * of 'already exist'. However, this case such that * the canonical name is "" causes many problems. * That is why the error of 'already exist' is * returned here. */ free(p1); return (GFARM_ERR_ALREADY_EXISTS); } else { *(lastc + 1) = '\0'; } } basename = gfarm_path_dir_skip(p1); if (basename == p1) /* "filename" */ dir = "."; else if (basename == p1 + 1) /* "/filename" */ dir = "/"; else { /* /.../.../filename */ p1[basename - 1 - p1] = '\0'; dir = p1; } /* Check the existence of the parent directory. */ e = gfarm_canonical_path(dir, &dir_canonic); if (e != NULL) goto free_p1; /* * check whether parent directory is writable or not. * XXX this isn't enough yet, due to missing X-bits check. */ if (dir_canonic[0] != '\0') { /* XXX "/" is always OK for now */ struct gfarm_path_info pi; e = gfarm_path_info_get(dir_canonic, &pi); if (e != NULL) goto free_dir_canonic; e = gfarm_path_info_access(&pi, GFS_W_OK); gfarm_path_info_free(&pi); if (e != NULL) goto free_dir_canonic; } *canonic_pathp = malloc(strlen(dir_canonic) + 1 + strlen(basename) + 1); if (*canonic_pathp == NULL) { e = GFARM_ERR_NO_MEMORY; goto free_dir_canonic; } /* * When the 'dir_canonic' is a null string, *canonic_pathp * will start with '/' incorrectly. */ if (dir_canonic[0] == '\0') strcpy(*canonic_pathp, basename); else sprintf(*canonic_pathp, "%s/%s", dir_canonic, basename); e = NULL; free_dir_canonic: free(dir_canonic); free_p1: free(p1); return (e); }
char * gfs_pio_create(const char *url, int flags, gfarm_mode_t mode, GFS_File *gfp) { char *e, *pathname; GFS_File gf; int pi_available = 0; mode_t mask; char *user; gfarm_timerval_t t1, t2; gfs_profile(gfarm_gettimerval(&t1)); user = gfarm_get_global_username(); if (user == NULL) { e = "gfarm_pio_create(): programming error, " "gfarm library isn't properly initialized"; goto finish; } #if 0 /* XXX - ROOT I/O opens a new file with O_CREAT|O_RDRW mode. */ if ((flags & GFARM_FILE_ACCMODE) != GFARM_FILE_WRONLY) { e = GFARM_ERR_OPERATION_NOT_SUPPORTED; /* XXX */ goto finish; } #endif mask = umask(0); umask(mask); mode &= ~mask; e = gfarm_url_make_path_for_creation(url, &pathname); if (e != NULL) goto finish; e = gfs_file_alloc(&gf); if (e != NULL) { free(pathname); goto finish; } /* gfs_pio_create() always assumes CREATE, TRUNC */ flags |= GFARM_FILE_CREATE | GFARM_FILE_TRUNC; if ((flags & (GFARM_FILE_TRUNC|GFARM_FILE_SEQUENTIAL)) != (GFARM_FILE_TRUNC|GFARM_FILE_SEQUENTIAL)) { /* MODE_READ is needed to re-calculate checksum. */ flags = (flags & ~GFARM_FILE_ACCMODE) | GFARM_FILE_RDWR; } else if ((flags & ~GFARM_FILE_ACCMODE) == GFARM_FILE_RDONLY) { flags = (flags & ~GFARM_FILE_ACCMODE) | GFARM_FILE_WRONLY; } gf->open_flags = flags; gf->mode = GFS_FILE_MODE_WRITE; if ((flags & GFARM_FILE_ACCMODE) == GFARM_FILE_RDWR) gf->mode |= GFS_FILE_MODE_READ; e = gfarm_path_info_get(pathname, &gf->pi); if (e != NULL && e != GFARM_ERR_NO_SUCH_OBJECT) { free(pathname); gfs_file_free(gf); goto finish; } if (e == NULL) { /* XXX unlink and re-create the file? */ free(pathname); e = gfarm_path_info_access(&gf->pi, GFS_W_OK); if (e != NULL) { gfarm_path_info_free(&gf->pi); gfs_file_free(gf); goto finish; } if (!GFARM_S_ISREG(gf->pi.status.st_mode)) { if (GFARM_S_ISDIR(gf->pi.status.st_mode)) e = GFARM_ERR_IS_A_DIRECTORY; else e = GFARM_ERR_OPERATION_NOT_SUPPORTED; gfarm_path_info_free(&gf->pi); gfs_file_free(gf); goto finish; } /* * XXX should check the follows: * - the mode is consistent among same job * - creator of the metainfo has same job id * - O_TRUNC / !O_TRUNC case */ mode |= GFARM_S_IFREG; if (GFARM_S_IS_PROGRAM(mode) != GFS_FILE_IS_PROGRAM(gf)) { gfarm_path_info_free(&gf->pi); gfs_file_free(gf); e = GFARM_ERR_OPERATION_NOT_PERMITTED; goto finish; } pi_available = 1; } if (!pi_available) { struct timeval now; gettimeofday(&now, NULL); gf->pi.pathname = pathname; gf->pi.status.st_mode = (GFARM_S_IFREG | mode); gf->pi.status.st_user = strdup(user); /* XXX NULL check */ gf->pi.status.st_group = strdup("*"); /* XXX for now */ gf->pi.status.st_atimespec.tv_sec = gf->pi.status.st_mtimespec.tv_sec = gf->pi.status.st_ctimespec.tv_sec = now.tv_sec; gf->pi.status.st_atimespec.tv_nsec = gf->pi.status.st_mtimespec.tv_nsec = gf->pi.status.st_ctimespec.tv_nsec = now.tv_usec * 1000; gf->pi.status.st_size = 0; gf->pi.status.st_nsections = 0; } *gfp = gf; gfs_uncachedir(); e = NULL; finish: gfs_profile(gfarm_gettimerval(&t2)); gfs_profile(gfs_pio_create_time += gfarm_timerval_sub(&t2, &t1)); return (e); }
char * gfarm_url_fragments_replicate(char *gfarm_url, int ndsthosts, char **dsthosts) { char *e, *gfarm_file, **srchosts, **edsthosts; int nsrchosts; gfarm_mode_t mode; int i, pid, *pids; struct gfarm_path_info pi; e = gfarm_url_make_path(gfarm_url, &gfarm_file); if (e != NULL) return (e); e = gfarm_path_info_get(gfarm_file, &pi); if (e != NULL) goto finish_gfarm_file; mode = pi.status.st_mode; gfarm_path_info_free(&pi); if (!GFARM_S_IS_FRAGMENTED_FILE(mode)) { e = GFARM_ERR_OPERATION_NOT_PERMITTED; goto finish_gfarm_file; } /* * XXX - if the owner of a file is not the same, permit a * group/other write access - This should be fixed in the next * major release. */ if (strcmp(pi.status.st_user, gfarm_get_global_username()) != 0) { e = gfarm_path_info_access(&pi, GFS_R_OK); if (e != NULL) { gfarm_path_info_free(&pi); free(gfarm_file); return (e); } mode |= 022; } e = gfarm_url_hosts_schedule(gfarm_url, "", &nsrchosts, &srchosts); if (e != NULL) goto finish_gfarm_file; edsthosts = malloc(sizeof(*edsthosts) * nsrchosts); if (edsthosts == NULL) { e = GFARM_ERR_NO_MEMORY; goto finish_srchosts; } gfarm_strings_expand_cyclic(ndsthosts, dsthosts, nsrchosts, edsthosts); pids = malloc(sizeof(int) * nsrchosts); if (pids == NULL) { e = GFARM_ERR_NO_MEMORY; goto finish_edsthosts; } /* * To use different connection for each metadb access. * * XXX: FIXME layering violation */ e = gfarm_metadb_terminate(); if (e != NULL) goto finish_pids; for (i = 0; i < nsrchosts; i++) { struct sockaddr peer_addr; char *if_hostname; char section_string[GFARM_INT32STRLEN + 1]; struct gfarm_file_section_info si; pid = fork(); if (pid < 0) break; if (pid) { /* parent */ pids[i] = pid; continue; } /* child */ /* * use different connection for each metadb access. * * XXX: FIXME layering violation */ e = gfarm_metadb_initialize(); if (e != NULL) _exit(1); /* reflect "address_use" directive in the `srchosts[i]' */ e = gfarm_host_address_get(srchosts[i], gfarm_spool_server_port, &peer_addr, &if_hostname); if (e != NULL) _exit(2); sprintf(section_string, "%d", i); e = gfarm_file_section_info_get(gfarm_file, section_string, &si); if (e != NULL) _exit(3); e = gfarm_file_section_replicate_from_to_internal( gfarm_file, section_string, mode & GFARM_S_ALLPERM, si.filesize, srchosts[i], if_hostname, edsthosts[i]); if (e != NULL) _exit(1); _exit(0); } while (--i >= 0) { int rv, s; while ((rv = waitpid(pids[i], &s, 0)) == -1 && errno == EINTR) ; if (rv == -1) { if (e == NULL) e = gfarm_errno_to_error(errno); } else if (WIFEXITED(s) && WEXITSTATUS(s) != 0) { e = "error happens on replication"; } } /* * recover temporary closed metadb connection * * XXX: FIXME layering violation */ if (e != NULL) { gfarm_metadb_initialize(); } else { e = gfarm_metadb_initialize(); } finish_pids: free(pids); finish_edsthosts: free(edsthosts); finish_srchosts: gfarm_strings_free_deeply(nsrchosts, srchosts); finish_gfarm_file: free(gfarm_file); return (e); }
char * gfarm_url_program_deliver(const char *gfarm_url, int nhosts, char **hosts, char ***delivered_paths) { char *e, **dp, *gfarm_file, *root, *arch, **canonical_hostnames; gfarm_mode_t mode; int i; struct gfarm_path_info pi; e = gfarm_url_make_path(gfarm_url, &gfarm_file); if (e != NULL) return (e); e = gfarm_path_info_get(gfarm_file, &pi); if (e != NULL) { free(gfarm_file); return (e); } mode = pi.status.st_mode; if (!GFARM_S_IS_PROGRAM(mode)) { gfarm_path_info_free(&pi); free(gfarm_file); return ("gfarm_url_program_deliver(): not a program"); } /* * XXX - if the owner of a file is not the same, permit a * group/other write access - This should be fixed in the next * major release. */ if (strcmp(pi.status.st_user, gfarm_get_global_username()) != 0) { e = gfarm_path_info_access(&pi, GFS_X_OK); if (e != NULL) { gfarm_path_info_free(&pi); free(gfarm_file); return (e); } mode |= 022; } gfarm_path_info_free(&pi); dp = malloc(sizeof(char *) * (nhosts + 1)); if (dp == NULL) { free(gfarm_file); return (GFARM_ERR_NO_MEMORY); } dp[nhosts] = NULL; e = gfarm_host_get_canonical_names(nhosts, hosts, &canonical_hostnames); if (e != NULL) { free(dp); free(gfarm_file); return (e); } /* XXX - this is too slow */ for (i = 0; i < nhosts; i++) { struct sockaddr peer_addr; struct gfs_connection *gfs_server; struct gfarm_file_section_info si; dp[i] = NULL; /* for error handling */ arch = gfarm_host_info_get_architecture_by_host( canonical_hostnames[i]); if (arch == NULL) { /* architecture of the hosts[i] is not registered */ e = "cannot deliver program to an unregistered host"; goto error; } /* XXX - which to use? `hosts[i]' vs `copies[j].hostname' */ e = gfarm_host_address_get(hosts[i], gfarm_spool_server_port, &peer_addr, NULL); if (e != NULL) { free(arch); goto error; } e = gfs_client_connection(canonical_hostnames[i], &peer_addr, &gfs_server); if (e != NULL) { free(arch); goto error; } e = gfs_client_get_spool_root(gfs_server, &root); if (e != NULL) { free(arch); goto error; } e = gfarm_full_path_file_section(root, gfarm_file, arch, &dp[i]); free(root); if (e != NULL) { free(arch); goto error; } e = gfarm_file_section_info_get(gfarm_file, arch, &si); if (e != NULL) { free(arch); goto error; } /* * replicate the program */ e = gfarm_file_section_replicate_to_internal(gfarm_file, arch, mode & GFARM_S_ALLPERM, si.filesize, hosts[i]); gfarm_file_section_info_free(&si); free(arch); if (e != NULL) goto error; } gfarm_strings_free_deeply(nhosts, canonical_hostnames); free(gfarm_file); *delivered_paths = dp; return (NULL); error: gfarm_strings_free_deeply(nhosts, canonical_hostnames); free(gfarm_file); gfarm_strings_free_deeply(i + 1, dp); *delivered_paths = NULL; return (e); }
gfarm_error_t gfs_chdir_canonical(const char *canonic_dir) { static int cwd_len = 0; static char env_name[] = "GFS_PWD="; static char *env = NULL; static int env_len = 0; int len, old_len; char *e, *tmp, *old_env; struct gfarm_path_info pi; e = gfarm_path_info_get(canonic_dir, &pi); if (e == NULL) { e = gfarm_path_info_access(&pi, X_OK); gfarm_path_info_free(&pi); } if (e != NULL) return (e); len = 1 + strlen(canonic_dir) + 1; if (cwd_len < len) { GFARM_REALLOC_ARRAY(tmp, gfarm_current_working_directory, len); if (tmp == NULL) return (GFARM_ERR_NO_MEMORY); gfarm_current_working_directory = tmp; cwd_len = len; } sprintf(gfarm_current_working_directory, "/%s", canonic_dir); len += sizeof(env_name) - 1 + GFARM_URL_PREFIX_LENGTH; tmp = getenv("GFS_PWD"); if (tmp == NULL || tmp != env + sizeof(env_name) - 1) { /* * changed by an application instead of this function, and * probably it's already free()ed. In this case, realloc() * does not work well at least using bash. allocate it again. */ env = NULL; env_len = 0; } old_env = env; old_len = env_len; if (env_len < len) { /* * We cannot use realloc(env, ...) here, because `env' may be * still pointed by environ[somewhere] (at least with glibc), * and realloc() may break the memory. So, allocate different * memory. */ GFARM_MALLOC_ARRAY(tmp, len); if (tmp == NULL) return (GFARM_ERR_NO_MEMORY); env = tmp; env_len = len; } sprintf(env, "%s%s%s", env_name, GFARM_URL_PREFIX, gfarm_current_working_directory); if (putenv(env) != 0) { if (env != old_env && env != NULL) free(env); env = old_env; env_len = old_len; return (gfarm_errno_to_error(errno)); } if (old_env != env && old_env != NULL) free(old_env); return (NULL); }